Vít Brunner
11/06/2025, 1:34 PMMarvin
11/06/2025, 1:34 PMMarvin
11/06/2025, 1:42 PM~/.prefect/storage — or whatever storage you’ve configured).
- The “Cache Key” field in the UI is populated from the task run state’s state_details.cache_key. In 3.4.24, it can show up empty even when caching is working. I couldn’t find a public bug report tied to 3.4.x for this display specifically, so this may be a UI gap rather than a backend issue.
How to verify the key is present server-side
Use the API to inspect the task run’s state details. Replace <TASK_RUN_ID> with the ID from the UI:
curl -s "$PREFECT_API_URL/api/task_runs/<TASK_RUN_ID>"
Look for
- .state.state_details.cache_key — the computed cache key (what the server used to look up a prior result)
- .state.name — should be “Cached” when a cache hit occurs
Related docs:
- Caching in Prefect 3
- Read a task run (REST API)
- Results and storage
Why the Cache Key might appear empty in the UI even when caching works
- The UI displays the cache key from the current state’s state_details. In some code paths, the state contains the right data but the UI doesn’t render it, so the field shows blank.
- If you customized caching (e.g., disabled caching, used a policy that returns no key) the key will be null — but since you’re seeing “Cached”, that’s not your case.
Where the result actually comes from
- Prefect stores the cached result in your configured result storage (local filesystem by default; S3, GCS, etc., if configured).
- The cache key maps to a previously completed task run’s result in the server database; Prefect then reads the result payload from the result store.
Tips if you want a visible/deterministic key
- You can set a custom cache policy so you always know and can log the key you expect:
from prefect import task
from prefect.cache_policies import INPUTS, TASK_SOURCE
# Example: cross-run caching based on inputs + code
@task(cache_policy=INPUTS + TASK_SOURCE)
def my_task(x, y):
...
Or define your own function:
from prefect import task
from prefect.cache_policies import CacheKeyFnPolicy
def my_cache_key(ctx, inputs):
# ctx includes run context; inputs is a dict of task args
return f"my-task:{inputs['x']}:{inputs['y']}"
@task(cache_policy=CacheKeyFnPolicy(my_cache_key))
def my_task(x, y):
...
Next steps
- If you can, grab a task run ID that shows “Cached” in the UI and check the API response for state.state_details.cache_key. If it’s present there but blank in the UI, that points to a UI display gap we can file.
- If it’s null in the API too, share how you’ve configured the task’s caching (the @task(...) options), and what result storage you’re using. I can help pinpoint why the key isn’t being attached.
If you’re up for it, feel free to paste:
- A screenshot of the task run detail (with the “Cached” badge)
- The output of the API call above for that same task run
Happy to dig in and, if needed, open a bug on your behalf.Vít Brunner
11/06/2025, 1:53 PM.state.state_details.cache_key has nothing. .state.data.storage_key has the path to the cache file.