Jashaul
03/16/2026, 5:53 AMMarvin
03/16/2026, 5:54 AMMarvin
03/16/2026, 5:57 AMprefect version
- Prefect Cloud or self-hosted server?
- Did this start after an upgrade or code change?
- Do you see flow logs but no task logs, or are all logs missing?
- In your flow code, are you calling tasks with my_task() (or .submit()), or using my_task.fn()?
Quick checks you can do now
- In the UI (Flow Run page → Graph tab), ensure the filters for “Tasks” are enabled. Sometimes the Graph filter hides tasks.
- Verify the client-side logging settings being used at runtime:
prefect config view --show-sources --show-defaults
Confirm:
- PREFECT_LOGGING_TO_API_ENABLED is True (otherwise logs won’t reach the UI)
- If you rely on print, either set @task(log_prints=True) or set PREFECT_LOGGING_LOG_PRINTS=True
- Ensure your code is creating task runs:
- Calling my_task.fn(...) bypasses orchestration and will not create task runs/logs or appear on the graph. Use my_task(...) or my_task.submit(...) inside a @flow.
Self-hosted server checks (Prefect 3.x)
- Make sure the task run recorder service is enabled on your API:
- PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED=true
- If this is disabled, task runs/logs/graph data won’t be persisted.
- If your flows have very large numbers of tasks, the server may cap what’s returned for the Graph:
- PREFECT_SERVER_FLOW_RUN_GRAPH_MAX_NODES and PREFECT_SERVER_FLOW_RUN_GRAPH_MAX_ARTIFACTS control limits (defaults are high, e.g., 10,000)
Minimal code sanity check
Try running this to confirm tasks are being recorded/logged:
from prefect import flow, task, get_run_logger
@task(log_prints=True, task_run_name="demo-task")
def t(x):
print(f"print from task: {x}")
logger = get_run_logger()
<http://logger.info|logger.info>(f"log from task: {x}")
return x * 2
@flow(log_prints=True)
def f():
a = t(1) # creates a task run
b = t.submit(2) # also creates a task run
# c = t.fn(3) # would NOT create a task run (bypasses orchestration)
return a, b.result()
if __name__ == "__main__":
f()
After running, open the flow run in the UI and check:
- Graph tab shows two task nodes
- Task-level logs appear under each task run
Common causes we see
- Using task.fn(...) instead of `task(...)`/`.submit(...)` (no task runs/logs/graph)
- PREFECT_LOGGING_TO_API_ENABLED is False in the runtime environment (no logs in UI)
- Relying on print without log_prints=True (prints won’t appear as logs)
- Self-hosted API with task run recorder service disabled
- UI Graph filters hiding tasks
Docs and references
- Tasks concept: Prefect 3.x Tasks
- Settings reference: Prefect 3.x Settings
- Logging customization: Logging customization
If you can share:
- Prefect version
- Cloud vs self-hosted
- A short snippet of how you call your tasks
- Output of prefect config view --show-sources --show-defaults for the logging-related keys
…I can pinpoint the cause quickly and suggest the exact fix.Jashaul
03/16/2026, 6:01 AMMarvin
03/16/2026, 6:01 AMMarvin
03/16/2026, 6:06 AMprefect version
curl -sSL $PREFECT_API_URL/admin/version
prefect config view --show-sources --show-defaults
- Worker runtime (the pod that runs your flow):
prefect version
prefect config view --show-sources --show-defaults
Please share the two Prefect versions (e.g., 3.4.2 on server, 3.6.0 on worker), and whether any are on 2.x.
2) Align versions
- Pin server and worker images to the same Prefect 3.x minor/patch (e.g., 3.6.0 on both). Avoid floating tags like 3-latest in production.
- In Kubernetes manifests/Helm, set the same image tag (e.g., prefecthq/prefect:3.6.0) for both the server API and for the worker/flow job image.
3) Check required services and connectivity on the server
- Ensure the task run recorder is enabled on the API:
- PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED=true
- Verify the API can accept WebSocket connections from your workers (load balancer/proxy must allow WS). Blocked WS = no task events created.
- For very large flows, verify graph limits aren’t filtering nodes:
- PREFECT_SERVER_FLOW_RUN_GRAPH_MAX_NODES (default is large, 10,000)
4) Check logging settings on the worker/runtime
- Confirm the worker/flow pods are actually sending logs to the API:
- PREFECT_LOGGING_TO_API_ENABLED=true (default is true)
- If you rely on print(), enable:
- Per task or flow: @task(log_prints=True) / @flow(log_prints=True)
- Or global: PREFECT_LOGGING_LOG_PRINTS=true
5) Quick sanity test
Run a tiny flow to verify task runs and task logs appear:
from prefect import flow, task, get_run_logger
@task(log_prints=True, task_run_name="demo-task")
def t(x):
print(f"print from task: {x}")
get_run_logger().info(f"log from task: {x}")
return x * 2
@flow(log_prints=True)
def f():
a = t(1) # creates a task run
b = t.submit(2) # creates a task run
# t.fn(3) would bypass orchestration (no task run/logs/graph)
return a, b.result()
if __name__ == "__main__":
f()
Open the flow run in the UI → Graph tab. You should see two task nodes and their logs.
If it’s still blank after aligning versions:
- Check API pod logs for TaskRunRecorder messages or WS errors.
- Check the flow pod logs for version check warnings or WS failures.
- Verify UI filters in the Graph tab aren’t hiding tasks.
References
- Tasks concept: Prefect 3.x Tasks
- Settings reference (logging, services, graph limits): Prefect 3.x Settings
- Logging customization: Logging customization
If you can share:
- The exact Prefect versions on server and worker
- Whether any side is on 2.x
- Output of prefect config view --show-sources --show-defaults for logging/service keys
…I can give you the precise steps to align and restore task logs/graph.Jashaul
03/16/2026, 6:29 AMMarvin
03/16/2026, 6:29 AMMarvin
03/16/2026, 6:32 AMkubectl -n <namespace> set image deploy/<worker-deployment-name> <container-name>=prefecthq/prefect:3.6.20
kubectl -n <namespace> rollout status deploy/<worker-deployment-name>
kubectl -n <namespace> exec deploy/<worker-deployment-name> -- prefect version
Tip: If you use a custom image, ensure it installs prefect==3.6.20.
2) Ensure flow-run jobs also use Prefect 3.6.20
The Kubernetes worker launches a new pod per flow run. That pod image must have the same Prefect version. There are two common ways this is set:
- Via the work pool base job template (most common)
- Export the default template, edit, and update:
prefect work-pool get-default-base-job-template --type kubernetes --file k8s.json
# edit k8s.json → set "image": "prefecthq/prefect:3.6.20"
prefect work-pool update "<your-pool-name>" --base-job-template k8s.json
- Via your deployment’s infrastructure overrides (if you set a custom image per deployment)
- Update the image there to prefecthq/prefect:3.6.20 or your custom image that has prefect==3.6.20.
- If you build your own image, pin Prefect inside it:
FROM python:3.11-slim
RUN pip install --no-cache-dir 'prefect==3.6.20'
# plus any extras you need, e.g., 'prefect[kubernetes]'
3) Verify versions at runtime
- Worker pod:
kubectl -n <namespace> exec deploy/<worker-deployment-name> -- prefect version
- Flow-run pod (after triggering a run), check logs for Prefect version or run a quick diagnostic:
from prefect import flow, task, get_run_logger, __version__ as PREFECT_VERSION
@task
def show():
get_run_logger().info(f"Prefect version in task: {PREFECT_VERSION}")
@flow
def f():
show()
if __name__ == "__main__":
f()
4) After aligning, if task logs/graph are still missing, double-check:
- Server setting: PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED=true
- Worker logs show no WebSocket/connectivity errors to the API
- Logging to API is on in flow pods: PREFECT_LOGGING_TO_API_ENABLED=true
- If you rely on prints, enable log_prints=True on flows/tasks or set PREFECT_LOGGING_LOG_PRINTS=true
If you want, share:
- The worker Deployment name/namespace and whether you use a custom image
- Whether your flow-run image is set via the work pool base job template or per-deployment
I can give you an exact patch command or template diff.