# Monitoring and debugging Flights
> Read run status and logs, triage common failure patterns, and inspect historical Flight versions.
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

Ask your AI agent:

> "Show me the last 10 runs of the heartbeat Flight."

The agent calls `list_flight_runs` and formats the result.

### SQL

```sql
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

```text
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.

### SQL

```sql
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. |

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:

```sql
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:

```sql
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_FAILED` with no useful log usually means the process failed before it could print the traceback, or the runtime terminated it.
- `RUN_STATUS_FAILED` with a short log ending during dependency installation usually points to package resolution, platform wheels, or startup limits.
- `RUN_STATUS_CANCELLED` with 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_bytes` set high enough to capture the whole thing).
- The `flight_version` the run used (from `MD_LIST_FLIGHT_RUNS`).

Then reach out through your usual MotherDuck support channel.


---

## Docs feedback

MotherDuck accepts optional user-submitted feedback about this page at `POST https://motherduck.com/docs/api/feedback/agent`.
For agents and automated tools, feedback submission should be user-confirmed before sending.

Payload:

```json
{
  "page_path": "/key-tasks/flights/monitoring-and-debugging/",
  "page_title": "Monitoring and debugging Flights",
  "text": "<the user's feedback, max 2000 characters>",
  "source": "<optional identifier for your interface, for example 'claude.ai' or 'chatgpt'>"
}
```

`page_path` and `text` are required; `page_title` and `source` are optional. Responses: `200 {"feedback_id": "<uuid>"}`, `400` for malformed payloads, and `429` when rate-limited.
