Monitoring and debugging Flights
A Flight that runs unattended needs to be observable. This page covers reading runs, reading logs, common failure patterns, and inspecting historical versions when something went wrong on a past run.
Listing runs
Every Flight tracks its run history. Get the recent runs newest-first:
- MCP / AI agent
- SQL
Ask your AI agent:
"Show me the last 10 runs of the heartbeat Flight."
The agent calls list_flight_runs and formats the result.
SELECT run_number, status, flight_version, created_at
FROM MD_LIST_FLIGHT_RUNS(flight_id := '<flight_id>')
ORDER BY run_number DESC
LIMIT 10;
Reading logs
Logs are the combined stdout and stderr captured during the run. Use them to verify what your Flight printed and to read tracebacks from failed runs.
- MCP / AI agent
- SQL
get_flight_run_logs(flight_id, run_number)
The response includes the run record and log content. When the log is large, the response is the tail; pass max_bytes to control the size cap.
SELECT logs
FROM MD_GET_FLIGHT_LOGS(flight_id := '<flight_id>', run_number := <n>);
Common failure patterns
Most failed runs fall into a handful of categories. Read the log first, then match the symptom:
| Symptom in the log | Likely cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named '<x>' | The package isn't in requirements.txt, or the name is misspelled. | Add or correct the entry, then update_flight (produces a fresh version). |
InvalidInputException: ... CreateShortLivedToken: Unable to resolve user | The Flight was created with an explicit access_token_name that doesn't exist in the environment the Flight is talking to (often a staging vs prod confusion). | Verify the token exists with SELECT token_name FROM md_access_tokens() in the MotherDuck UI SQL editor or DuckDB CLI against the same MotherDuck environment. |
duckdb.duckdb.IOException: ... Could not find file or Catalog Error: ... does not exist | The Flight uses a database it can't reach with the permissions of the identity it runs as, or the data isn't there. | Check the privileges of the user or service account the Flight runs as and whether the source files or shares are attached. |
| Schedule didn't fire | The Flight has no schedule_cron, or the cron expression is in local time when it should be UTC. | Check schedule_cron on MD_LIST_FLIGHTS() and convert the intended time to UTC. |
| Run uses "old" source after an update | The run started before the update landed and locked to the previous version. | Trigger a fresh run; subsequent runs use the latest version. |
pip install errors during startup | A requirement can't be resolved (typo, yanked version, missing platform wheel). | Check PyPI for the exact package and version, and pin to a version with a Linux wheel. |
| Run cancelled unexpectedly | Someone clicked Cancel in the UI, or the run hit a timeout. | Check the trigger and the duration in the run record. |
Run fails near the end of a large build with little or no log; the run record shows a non-zero exit_code | The runtime hit its memory ceiling and was OOM-killed. | Lower peak memory: push heavy compute into SQL, process in bounded chunks, and lower dbt --threads. See runtime limits. |
If the failure doesn't match any of these, capture the full traceback from the log and the run record before re-running — that's the information support needs.
Inspecting a specific version
If a past run misbehaved and the current Flight source has moved on, you can still see exactly what that run executed.
List versions:
SELECT version, created_at, source_code
FROM MD_LIST_FLIGHT_VERSIONS(flight_id := '<flight_id>')
ORDER BY version DESC;
Or get a single version with full content:
SELECT *
FROM MD_GET_FLIGHT_VERSION(flight_id := '<flight_id>', version_number := <n>);
Through the MCP server, the equivalent calls are list_flight_versions and get_flight with a version argument.
The flight_version column on MD_LIST_FLIGHT_RUNS tells you which version a given run used. Combine the two to read the exact source and requirements that produced a failed run.
When the log isn't enough
Some failures don't surface much stdout/stderr — for example, an OOM kill or a process the runtime terminated. Start with the run record from MD_LIST_FLIGHT_RUNS: status, flight_version, the started_at/ended_at timings, the config the run used, and the process exit_code:
RUN_STATUS_FAILEDwith no useful log usually means the process failed before it could print the traceback, or the runtime terminated it.RUN_STATUS_FAILEDwith a short log ending during dependency installation usually points to package resolution, platform wheels, or startup limits.RUN_STATUS_CANCELLEDwith a manual trigger is someone clicking the button or calling the cancel API.
Match the pattern, add observability to your main() (a log line at each milestone, a print of memory usage if you suspect OOM), and re-run.
Getting help
For issues that aren't in the failure table above, gather:
- The Flight's name or ID.
- The failing run number.
- The full log content (use
max_bytesset high enough to capture the whole thing). - The
flight_versionthe run used (fromMD_LIST_FLIGHT_RUNS).
Then reach out through your usual MotherDuck support channel.