Anish S
06/09/2026, 12:37 PMMarvin
06/09/2026, 12:38 PMMarvin
06/09/2026, 12:41 PMPENDING state and a usable start timestamp. Subflow runs can still appear even when task runs do not, because they come from flow-run records and are queried differently.
Most likely cause: your task runs are executing, but their task-run state/timestamps are not being recorded in a way the 3.7 DAG query accepts.
What to check:
1. Inspect a flow run’s task runs in the DB / API
For affected flow runs, confirm task runs have:
- state_type not equal to PENDING
- start_time or expected_start_time populated
If task runs stay PENDING, they will not appear in the DAG in 3.7.
2. Check worker / flow logs for task-run event or state-recording issues
In particular, look for errors around:
- task run state updates
- event emission
- API communication from the ECS task back to Prefect
3. If you use custom states/names, verify behavior after upgrade
Prefect changed some event naming behavior in newer 3.7 releases, so anything depending on custom state/event names may no longer behave the same way.
4. Upgrade to the latest 3.7.x, not just 3.7.0
There were fixes in the 3.7 line related to event/state handling. If you’re on an early 3.7 release, upgrading further is a good first step.
Why this happens:
- The DAG view in 3.7 filters out task runs with PENDING state.
- It also requires a task run to have a start-related timestamp.
- Subflows can still show because they’re represented as flow runs, not plain task runs.
So the fix is usually:
- make sure task runs are getting proper state transitions recorded
- make sure the worker/flow process can report those states back to the API
- update to latest 3.7.x
Useful references:
- Prefect releases: Prefect releases
- Prefect 3 docs: Prefect docs
If you want, I can help you narrow this down quickly if you share:
- your exact Prefect version before/after
- whether you use ConcurrentTaskRunner, ProcessPoolTaskRunner, or another runner
- whether these are regular tasks or mapped tasks
- one example flow where tasks execute successfully but don’t appear in the DAGAnish S
06/09/2026, 1:18 PMcreating task run... logs.Marvin
06/09/2026, 1:27 PMMarvin
06/09/2026, 1:29 PMpython
import asyncio
from prefect.client.orchestration import get_client
from prefect.client.schemas.filters import TaskRunFilter, TaskRunFilterFlowRunId
FLOW_RUN_ID = "your-flow-run-id"
async def main():
async with get_client() as client:
task_runs = await client.read_task_runs(
task_run_filter=TaskRunFilter(
flow_run_id=TaskRunFilterFlowRunId(any_=[FLOW_RUN_ID])
)
)
for tr in task_runs:
print(tr.id, tr.name, tr.state_type, tr.start_time)
asyncio.run(main())
REST API
bash
curl -X POST "$PREFECT_API_URL/task_runs/filter" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"task_runs": {
"flow_run_id": { "any_": ["<FLOW_RUN_ID>"] }
}
}'
A very important detail:
If the “missing tasks” are actually tasks that launch subflows, then in 3.7 those parent task runs are intentionally hidden from the DAG, and you only see the subflow run node. That matches your symptom exactly: subflow runs show, task nodes do not.
So first question:
- Are the missing nodes ordinary `@task`s?
- Or are they `@task`s / calls that wrap or invoke @flow?
Also, fatal: not a git repository is probably unrelated unless your code explicitly shells out to git.
If you want, paste one minimal example of a “missing task” and I can tell you whether it’s expected DAG behavior or a bug.Anish S
06/09/2026, 2:01 PM@task s.
When I tried doing curl for task runs.
On the main flow, the api returns, only the subflow runs, but no task runs.
On the subflows, the api returns nothing because they only have tasks in them.Marvin
06/09/2026, 2:01 PMMarvin
06/09/2026, 2:04 PM/task_runs/filter returns no normal task runs, then Prefect is not recording them in the API/database.
Most likely causes in 3.7.4:
1. Task run events are not being persisted
Prefect 3 records task runs through an event/recorder pipeline. If that recorder is unhealthy or disabled, you can see execution logs like creating task run, but nothing shows up via API.
2. Only subflow-invocation task runs are making it through
That fits what you're seeing: parent flow shows the subflow launcher task runs, but ordinary tasks inside subflows never get persisted.
Please check these:
Is the task run recorder service enabled/running?
- If self-hosted server, verify the task_run_recorder service is healthy.
- If you have server logs, search for task_run_recorder.
Check these settings on the server side
bash
PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED=true
If you set any custom server service settings, that’s the first thing I’d inspect.
Wait a few seconds, then query again
There is batching/flush delay, so retry after ~5–10 seconds.
Query one known subflow run ID directly
Use the subflow’s flow run id and filter task runs by that exact ID again. If still empty after delay, those task runs are not being persisted at all.
At this point, the most useful next step is to determine whether you're using:
- Prefect Cloud or self-hosted server
- any custom task runner / distributed task execution mode
Because if this is self-hosted, I’d focus immediately on the server-side recorder service. If it’s Cloud, this starts to look more like a 3.7.4 regression or an execution-mode-specific bug.
If you want, I can give you the one fastest command/check for either:
- Prefect Cloud, or
- self-hosted server.Anish S
06/09/2026, 2:31 PMprefect-aws ecs-worker deploy-events and configure the PREFECT_INTEGRATIONS_AWS_ECS_OBSERVER_SQS_QUEUE_NAME environment variable on your worker to point to the deployed queue.
@Marvin Does it have to do anything with this warning?Marvin
06/09/2026, 2:31 PMMarvin
06/09/2026, 2:31 PM@task runs are absent from /task_runs/filter
What that warning affects:
- ECS task state replication
- detecting crashed/killed ECS jobs
- infrastructure-level events
What your symptom points to instead:
- Prefect task runs are being created in execution logs
- but not persisted/read back from the API
That is a different path.
You can fix the ECS warning by following the worker message:
- deploy the queue with the prefect-aws ECS worker helper
- set PREFECT_INTEGRATIONS_AWS_ECS_OBSERVER_SQS_QUEUE_NAME
Docs:
- prefect-aws integration docs
Given your symptoms, I’d focus next on:
1. whether you are on Prefect Cloud or self-hosted server
2. whether the task run recorder service is healthy
3. whether this reproduces with a tiny flow of just:
- one parent flow
- one subflow
- two plain `@task`s inside the subflow
If you tell me Cloud vs self-hosted, I’ll give you the shortest next check.Anish S
06/09/2026, 2:32 PMMarvin
06/09/2026, 2:33 PMMarvin
06/09/2026, 2:33 PMtask_run_recorder
- record_bulk_task_run_events
- IntegrityError
- dropped
- retry
Also verify this is enabled on the server:
bash
PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED=true
If you run Prefect server yourself, also wait a few seconds after the flow finishes before querying /task_runs/filter, since recording is batched.
What I’d do next, in order:
1. Confirm recorder enabled
bash
echo $PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED
2. Inspect server logs
Look for any task-run-recorder errors/warnings around the time the flow ran.
3. Restart the server services
If the recorder got wedged, a restart may temporarily restore task-run persistence.
4. Run a tiny repro flow
A flow with:
- one @task
- one subflow
- one @task inside the subflow
Then compare:
- /flow_runs/filter
- /task_runs/filter
If you want, I can give you a very short repro flow plus the exact curl calls to validate recorder behavior.Anish S
06/09/2026, 2:52 PMMarvin
06/09/2026, 2:52 PMMarvin
06/09/2026, 2:53 PM/task_runs/filter shows only subflow launcher task runs and no ordinary tasks, I’d treat this as either:
- a 3.7.4 self-hosted bug/regression, or
- something specific about how those tasks are being executed
Fastest isolation step: run this minimal repro on the same setup.
python
from prefect import flow, task
@task
def t1():
return 1
@task
def t2(x):
return x + 1
@flow
def child():
x = t1()
t2(x)
@flow
def parent():
t1()
child()
t2(5)
if __name__ == "__main__":
parent()
Then check:
- does the parent flow show only the child subflow node?
- do any plain tasks appear in /task_runs/filter?
If no plain tasks appear even in this minimal case, that strongly points to a server/version issue rather than your code.
At that point, I’d recommend either:
1. upgrade to the latest available 3.7.x / current 3.x, or
2. open/check a GitHub issue because this does not look like expected behavior
Releases:
- Prefect releases
- Prefect issues
If you want, I can do one quick pass through existing GitHub issues/discussions for this exact symptom.Anish S
06/09/2026, 3:00 PMMarvin
06/09/2026, 3:00 PMMarvin
06/09/2026, 3:01 PMCompleted()
- flow finishes Completed()
So this is not a “task never ran” problem.
If that task still does not appear in /task_runs/filter, then the likely problem is:
the task run exists in memory during execution, but is not being persisted to the API/database in your self-hosted 3.7.4 setup.
Given that this is a single normal task, I would stop looking at ECS/SQS and focus on the server/API layer.
Two fast checks:
1. Query task runs by flow-run id again after completion with a delay
Wait 10–15 seconds after the flow completes, then call:
bash
curl -X POST "$PREFECT_API_URL/task_runs/filter" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"task_runs": {
"flow_run_id": { "any_": ["07d6791b-86e4-4a43-a15b-8b2dc632605e"] }
}
}'
If still empty, persistence is failing.
2. Check the database directly
If you can access the DB, run:
sql
select id, flow_run_id, name, state_type, start_time
from task_run
where flow_run_id = '07d6791b-86e4-4a43-a15b-8b2dc632605e';
Interpretation:
- rows exist in DB -> API/filter/UI issue
- no rows in DB -> server never persisted task runs
At this point, based on everything you shared, my best guess is:
- this is a self-hosted 3.7.4 regression/bug affecting task-run persistence
Since GitHub search is failing on my side right now, I can’t verify an existing issue, but your reproduction is strong.
My practical recommendation:
- upgrade your self-hosted server/API to the latest available 3.x first
- if you cannot, pin back to the version that worked
- and if needed, open a GitHub issue with exactly this repro:
- self-hosted
- 3.7.4
- ECS workers
- normal @task executes and logs Completed()
- /task_runs/filter returns no task runs for the flow run
- subflow launcher task runs may appear, ordinary task runs do not
Issue tracker:
- Prefect issues
If you want, I can help you draft the issue text in 5–6 lines.Anish S
06/09/2026, 3:45 PMMarvin
06/09/2026, 3:45 PMMarvin
06/09/2026, 3:46 PMTask runs execute normally but are not persisted in self-hosted Prefect 3.7.4
Body
text
### Bug summary
In a self-hosted Prefect 3.7.4 deployment, normal `@task` runs execute and log successfully, but no corresponding rows are written to the `task_run` table and `/task_runs/filter` returns no task runs.
Subflow runs do appear, but ordinary task runs do not.
### Version info
- Prefect version: 3.7.4
- Deployment type: self-hosted
- Workers: ECS workers on AWS
- Server started with: `prefect server start`
### What I expected
Normal `@task` runs should be persisted and visible:
- in the `task_run` table
- via `/task_runs/filter`
- in the run DAG
### What happened
Task logs show normal execution and completion, for example:
```text
14:55:20.453 | INFO | Flow run 'chi6-matalas-x' - Beginning flow run 'chi6-matalas-x' for flow 'mesh-test-flow'
14:55:20.512 | INFO | Task run 'task_update_test_environment-67e' - Updating workflow testing environment json file
14:55:26.568 | INFO | Task run 'task_update_test_environment-67e' - JSON file created: /data/test_outputs/files.json
14:55:26.573 | INFO | Task run 'task_update_test_environment-67e' - Finished in state Completed()
14:55:27.573 | INFO | Flow run 'chi6-matalas-x' - Finished in state Completed()
However:
- POST /task_runs/filter for that flow run returns no normal task runs
- querying the DB shows no rows in task_run for that flow_run_id
### Minimal example
python
from prefect import flow, task
@task
def t1():
print("hello")
@flow
def test_flow():
t1()
if __name__ == "__main__":
test_flow()
### Additional notes
- This worked in 3.4.10
- After upgrading to 3.7.x, only subflow runs show in the DAG
- Ordinary task runs are missing from both the UI and API
- PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED is not set explicitly
- I do see this ECS warning, but it seems unrelated:
text
SQS queue 'prefect-ecs-tasks-events' does not exist in region 'default'. This worker will continue to submit ECS tasks, but event replication and crash detection will not work.
### Verification performed
- Waited after flow completion before querying
- Queried /task_runs/filter by flow_run_id
- Checked the task_run table directly: no rows exist for affected flow runs
- Server logs do not obviously show task_run_recorder errors
```
If you want, I can also make this shorter and more maintainer-friendly with a “Steps to reproduce / Actual / Expected” format.Anish S
06/09/2026, 6:07 PM174408.767 | ERROR | prefect.server.utilities.postgres_listener - Failed to establish raw asyncpg connection for LISTEN/NOTIFY: bad query field: 'EO|Bs8$ctC@prefect.abcdef.us-east-1.rds.amazonaws.com:5432/postgres'Seems like it has to do with our PG Password:
'postgresql+asyncpg://prefect:D_~b$yy?EO|Zs8$ctC@prefect.abcdef....See how everything before
? has been ignored.
prefect server serivces ls,
Available Services
│ TaskRunRecorder │ ✓ PREFECT_SERVER_SERVICES_TASK_RUN_RECORDER_ENABLED
│ EventLogger │ x PREFECT_SERVER_SERVICES_EVENT_LOGGER_ENABLED
│ EventPersister │ ✓ PREFECT_SERVER_SERVICES_EVENT_PERSISTER_ENABLED
│ ReactiveTriggers │ ✓ PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED
│ Actions │ ✓ PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED
│ Distributor │ ✓ PREFECT_API_EVENTS_STREAM_OUT_ENABLED
│ LogDistributor │ x PREFECT_SERVER_LOGS_STREAM_OUT_ENABLED
Any insight? @MarvinMarvin
06/09/2026, 6:07 PMMarvin
06/09/2026, 6:07 PM? starts the query string, so a password like:
text
D_~b$yy?EO|Zs8$ctC
must be percent-encoded before being embedded in:
text
<postgresql+asyncpg://user:password@host:5432/dbname>
Otherwise Prefect / SQLAlchemy / asyncpg may parse everything after ? as URL query content instead of password.
That explains this error:
text
Failed to establish raw asyncpg connection for LISTEN/NOTIFY: bad query field ...
because the listener code uses the DB URL and the parsed URL is malformed.
Why things still mostly work
- normal DB access may still work through one code path
- but the raw asyncpg LISTEN/NOTIFY connection used by postgres_listener is stricter and fails
Fix
Percent-encode the password in the URL.
For example, encode special characters like:
- ? -> %3F
- | -> %7C
- $ -> %24
- ~ usually ok, but encoding is also fine
So the password:
text
D_~b$yy?EO|Zs8$ctC
should become something like:
text
D_~b%24yy%3FEO%7CZs8%24ctC
Then use that in your connection string.
Example:
text
<postgresql+asyncpg://prefect:D_~b%24yy%3FEO%7CZs8%24ctC@host:5432/postgres>
Best practice
If possible:
- avoid putting raw credentials directly into URLs
- or regenerate a DB password without reserved URL characters
Python can encode it with:
python
from urllib.parse import quote
print(quote("D_~b$yy?EO|Zs8$ctC", safe=""))
This should help:
- remove the postgres_listener error
- restore LISTEN/NOTIFY behavior correctly
Relevant docs:
- Self-hosted Prefect
- SQLAlchemy database URLs
So short answer: yes, this is almost certainly your password needing URL encoding.Anish S
06/09/2026, 6:10 PMpostgres_listener used for?Marvin
06/09/2026, 6:10 PMMarvin
06/09/2026, 6:10 PMpostgres_listener is used for Postgres LISTEN/NOTIFY-based signaling inside self-hosted Prefect.
In practice, it helps Prefect services react to DB-backed events without polling as much.
Most relevant uses are around:
- coordinating server-side services
- reacting to newly persisted events / notifications
- trigger / automation-related wakeups
- internal event distribution paths
That’s why things can still mostly work even when it errors:
- core API/database operations can still succeed
- but some reactive/background behavior may be degraded or less efficient
So if postgres_listener is broken, you may see:
- noisier logs
- delayed or degraded automations/triggers/event handling
- fallback behavior instead of efficient notifications
But it usually does not block basic flow/task execution by itself.
Given your service list, this is most relevant to:
- ReactiveTriggers
- Actions
- event-related background services
So I would still fix it, even if runs look healthy.Anish S
06/09/2026, 6:38 PMInvalidAuthorizationSpecificationError.
My connection URL has changed to
> Set 'PREFECT_API_DATABASE_CONNECTION_URL' to
> 'postgresql+asyncpg://prefect:H_~b%24yy%3FEO%7CBs8%24ctC@prefect.abcde.us-east-1.rds.amazonaws.com:5432/postgres'.Marvin
06/09/2026, 6:38 PMMarvin
06/09/2026, 6:39 PMtext
<postgresql+asyncpg://prefect:H_~b%24yy%3FEO%7CBs8%24ctC>...
It should be:
text
<postgresql+asyncpg://prefect:H_~b%24yy%3FEO%7CBs8%24ctC@host:5432/postgres>
Wait — actually the key thing is whether there is an @ after the password.
Valid URL shape is:
text
postgresql+asyncpg://<username>:<password>@<host>:<port>/<database>
So check all of these carefully:
1. Username/password separator
Must be username:password
2. Password/host separator
Must be @
3. No extra quotes/brackets
The env var value should just be the raw URL
Correct example:
text
<postgresql+asyncpg://prefect:H_~b%24yy%3FEO%7CBs8%24ctC@prefect.abcdef.us-east-1.rds.amazonaws.com:5432/postgres>
If you already have that format and still get InvalidAuthorizationSpecificationError, then the next likely causes are:
- username is wrong
- database name is wrong
- password was encoded twice
- password in RDS is actually different from what you think
One subtlety:
- only encode the password portion
- do not encode the whole URL
You can verify with Python:
python
from urllib.parse import quote
password = "H_~b$yy?EO|Bs8$ctC"
print(quote(password, safe=""))
Then place that output only into:
text
<postgresql+asyncpg://prefect:<encoded_password>@host:5432/postgres>
If you want, paste the URL with host partially redacted like:
text
<postgresql+asyncpg://prefect:***@host:5432/postgres>
and I can sanity-check the structure.Anish S
06/09/2026, 6:41 PMInvalidAuthorizationSpecificationError.
asyncpg.exceptions.InvalidAuthorizationSpecificationError: no pg_hba.conf entry for host "172.172.17.17", user "prefect", database "postgres", no encryption
ERROR: Application startup failed. Exiting.My connection URL has changed to
Set 'PREFECT_API_DATABASE_CONNECTION_URL' to
'postgresql+asyncpg://prefect:H_~b%24yy%3FEO%7CBs8%24ctC@prefect.abcde.us-east-1.rds.amazonaws.com:5432/postgres'.
Marvin
06/09/2026, 6:41 PMMarvin
06/09/2026, 6:41 PMtext
no pg_hba.conf entry for host "...", user "prefect", database "postgres", no encryption
means:
the server is requiring SSL/TLS, but the asyncpg connection used by Prefect’s postgres listener is connecting without encryption.
So:
- password encoding was needed
- but now the blocker is SSL mode / TLS requirements
For RDS, you usually need SSL enabled.
Also, your URL should be structurally:
text
<postgresql+asyncpg://prefect:<encoded_password>@prefect.abcde.us-east-1.rds.amazonaws.com:5432/postgres?ssl=require>
A few important notes:
1. No angle brackets / Slack mailto formatting
The real env var must be plain text only.
2. The username should not be outside the authority
It should be:
text
<postgresql+asyncpg://user:pass@host:port/db>
not
text
<postgresql+asyncpg://user>>:pass...
3. Add SSL requirement
For RDS, try:
text
?ssl=require
So the likely correct value is:
text
<postgresql+asyncpg://prefect:H_~b%24yy%3FEO%7CBs8%24ctC@prefect.abcde.us-east-1.rds.amazonaws.com:5432/postgres?ssl=require>
If that still fails, use the RDS CA / SSL config appropriate for your environment, but ssl=require is the first thing to try.
So short version:
- your earlier problem was password parsing
- your current problem is TLS required by Postgres/RDS
- add ?ssl=require to a correctly formed URL
Relevant docs:
- SQLAlchemy database URLs
- PostgreSQL SSL support
- RDS PostgreSQL SSL