Robert Szomolanyi
08/12/2025, 9:22 AMMarvin
08/12/2025, 9:22 AMMarvin
08/12/2025, 9:32 AMstr
case happened to keep the reference, hence the arrows. Yes, slightly maddening. No, you didn’t do anything wrong.
Ways to make the arrows reliable:
- Use futures (explicit dependencies)
from prefect import task, flow
@task
def create_value() -> int:
return 1
@task
def process_value(x: int):
print("processing...", x)
@flow
def t1():
val = create_value.submit()
process_value.submit(val)
if __name__ == "__main__":
t1()
Passing `PrefectFuture`s guarantees the server records the upstream→downstream link, so the UI draws the edge every time.
- Persist the producer’s result (helps provenance for inline calls)
@task(persist_result=True)
def create_value() -> int:
return 1
Or set PREFECT_RESULTS_PERSIST_BY_DEFAULT=true
for the run. Persisting results gives the recorder something concrete to reference in task_inputs
, which usually restores the edge for synchronous create_value()
→ process_value(...)
. Caveat: this increases result storage usage.
Practical notes:
- This isn’t tied to OSS vs Cloud; it’s about how Prefect records task_inputs in 3.4.8. With simple Python primitives, provenance can be lossy.
- Even without arrows, execution order in your example is still correct; it’s just the visualization that’s missing the link.
- If the graph matters to you and you like the synchronous style, the persist_result=True
route is the least disruptive. If you want concurrency and robust graphs, use .submit()
.
If you’d like, I can open an issue with a minimal repro noting the int vs str discrepancy you observed in 3.4.8.Robert Szomolanyi
08/12/2025, 9:45 AMMarvin
08/12/2025, 9:46 AMMarvin
08/12/2025, 9:47 AM### Bug summary
In Prefect 3.4.8 (OSS, on-prem), the flow run UI sometimes does not draw dependency edges between tasks when a task’s output is a primitive `int` passed to another task via a synchronous call inside a flow. The same pattern with a `str` shows the edge as expected.
Using futures (`.submit()`) or enabling `persist_result=True` restores the edge, so this appears to be a provenance/task_inputs recording issue for primitive ints in synchronous calls.
### Minimal reproducible examples
Works (edge shown):
```python
from prefect import task, flow
@task
def create_value() -> str:
return "1"
@task
def process_value(x: str):
print("processing...", x)
@flow(log_prints=True)
def t1():
val = create_value()
process_value(val)
if __name__ == "__main__":
t1()
Does not show edge (no arrow between tasks):
python
from prefect import task, flow
@task
def create_value() -> int:
return 1
@task
def process_value(x: int):
print("processing...", x)
@flow(log_prints=True)
def t1():
val = create_value()
process_value(val)
if __name__ == "__main__":
t1()
Workarounds that do show edges:
- Use futures:
python
val = create_value.submit()
process_value.submit(val)
- Or persist results:
python
@task(persist_result=True)
def create_value() -> int:
return 1
### Expected behavior
The UI graph should display a dependency edge for downstream tasks whenever they receive the output of an upstream task, regardless of the value’s primitive type (int vs str) or whether the call is synchronous.
### Actual behavior
With synchronous task calls, passing a primitive int
loses the visible dependency edge in the UI, whereas passing a str
does not.
### Additional context
- The UI path where this is visible: /runs/flow-run/<id>
- This seems tied to how task_inputs
are recorded for small primitive values; they appear to be inlined rather than recorded as a reference to the upstream task run, so the edge is not drawn.
### Environment
- Prefect: 3.4.8 (OSS, on-prem)
- Python: [please fill in]
- Orchestration DB: [please fill in, e.g., Postgres version]
- How the flow is run: local __main__
execution (no deployment)
### Screenshots / logs (optional)
N/A
### Notes
Even without edges, execution order is correct; this report is about visualization. The issue does not reproduce when using .submit()
or persist_result=True
.
```
If you want, I can turn this into a gist you can one-click copy, but alas, no robotic finger to press “Create issue” for you.