---
name: dbt-failed-runs-and-stale-sources
description: "Every morning: dbt Cloud runs that failed since yesterday with the step and model that broke, plus sources past their freshness threshold, and a retry question. Use when the user asks for this, or when it runs on a schedule."
---

# dbt Cloud failed runs and stale sources

Every morning: dbt Cloud runs that failed since yesterday with the step and model that broke, plus sources past their freshness threshold, and a retry question.

When the overnight dbt build fails, the warehouse keeps serving yesterday's tables and nothing looks broken. When a source stops loading, dbt itself runs fine on stale data. Either way the first person to notice is usually someone in a meeting asking why the numbers have not moved.

The agent reads failed runs from the Administrative API of the dbt platform (the product formerly called dbt Cloud), pulls the failing models from the run's `run_results.json`, and checks source freshness through the Discovery API. The card separates "the job broke" from "the data is late", since they have different owners, and asks whether to retry the failed run.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- A dbt platform service token with read access to jobs and runs, plus Metadata Only access for the Discovery API, in `DBT_TOKEN`, with the account ID and your access URL. The Discovery API is on the Starter, Enterprise and Enterprise+ plans.
- Or the dbt MCP server (`dbt-mcp`, maintained by dbt Labs) configured with the same token.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **List failed runs** (dbt): `GET https://<access-url>/api/v2/accounts/{account_id}/runs/?status=20&order_by=-finished_at&limit=50` (status 20 is error; the access URL, `<prefix>.<region>.dbt.com`, is under Account settings > Access URLs) and keep runs finished since yesterday morning. With the dbt MCP server, `list_jobs_runs` does the same.
2. **Find the failing models** (dbt): For each failed run, `GET .../runs/{run_id}/artifacts/run_results.json` and keep results with `status` `error` or `fail` (tests), with `unique_id` and the first line of `message`. The MCP tool `get_job_run_error` returns the same.
3. **Check source freshness** (dbt): Query the Discovery API (`https://<prefix>.metadata.<region>.dbt.com/graphql`, for example `abc123.metadata.us1.dbt.com`) with `environment(id: <prod env>) { applied { sources(first: 500) { edges { node { sourceName name freshness { freshnessChecked freshnessStatus } } } } } }` and keep sources whose `freshnessStatus` is `warn` or `error`.
4. **Check for a later success** (dbt): For each failed job, read its newest run (`GET .../runs/?job_definition_id=<id>&order_by=-finished_at&limit=1`). A success there means the job has recovered; list it under Recovered.
5. **Ask about a retry**: Post failed jobs and stale sources and ask what to do. Only after a yes, call `POST .../runs/{run_id}/retry/` (or the MCP `retry_job_run`), which reruns from the failed step. A model error needs a code fix first; say so.

## Route B: the browser

### What you need

- Signed in to the dbt platform with a role that can view runs and open Explore for the production environment (Developer or Account Admin). Explore needs a Starter, Enterprise or Enterprise+ plan.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://cloud.getdbt.com/. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **Open Run history**: Sign in at cloud.getdbt.com or your account's access URL and pick the account and project. Open **Orchestration** > **Run history** (older navigation: **Deploy** > **Run history**) and filter **Status** to `Error`. Keep runs whose finish time is since yesterday morning.
2. **Read each failed run**: Open the run. The step list shows which command failed (`dbt build` in most jobs); expand it and read the summary lines, which name the models or tests that errored, the first error line and how many models were skipped. The **Artifacts** tab holds `run_results.json` if the log is long.
3. **Check for a later success**: Back in Run history, filter by the same job (click the job name, then its **Run history**). If a newer run shows `Success`, the job has recovered; list it under Recovered instead of Failed.
4. **Check source freshness**: Open **Explore** with the production environment selected and go to **Sources** (or **Resources** > **Sources**). The list shows each source's freshness status; keep tables marked `Warn` or `Error`, with the source name and the last loaded time.
5. **Ask before retrying**: Post failed jobs and stale sources in separate sections and ask what to do. Only after a yes, open the failed run and click **Retry from failure**; a model error needs a code fix first, so say so.

Note: Run history shows one account at a time; with several accounts, switch in the account menu and repeat. Freshness only appears in Explore when a job in that environment runs source freshness checks.

## The report

- **Failed runs**: job, failing step, models or tests that errored with the first error line.
- **Recovered**: runs that failed and later succeeded.
- **Stale sources**: source and table with warn or error freshness.
- The question: retry, fix first, or leave.

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "dbt-failed-runs-and-stale-sources/<date of this run, e.g. 2026-10-16>",
  "item_key": "dbt-failed-runs-and-stale-sources",
  "project": "Acme dbt",
  "source": "dbt Cloud failed runs and stale sources skill",
  "kind": "action",
  "title": "Prod nightly failed on fct_orders, 2 sources stale",
  "summary": "The **Prod nightly** run failed at `dbt build`: model **fct_orders** errored. Sources **stripe.charges** (error) and **hubspot.deals** (warn) are past their freshness threshold.",
  "action": {
    "request": "fct_orders fails on a missing column, so a retry will fail again until the model is fixed. Retry anyway, or wait for a fix?",
    "options": [
      "Retry the run",
      "Show the full error",
      "I will fix fct_orders",
      "Leave it"
    ]
  },
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Item",
          "Status",
          "Detail"
        ],
        "rows": [
          [
            "Prod nightly, model fct_orders",
            "Error",
            "column \"discount_code\" does not exist"
          ],
          [
            "Prod nightly, 14 downstream models",
            "Skipped",
            "Depend on fct_orders"
          ],
          [
            "Source stripe.charges",
            "Freshness error",
            "Fivetran sync paused since yesterday 06:00"
          ],
          [
            "Source hubspot.deals",
            "Freshness warn",
            "Last load later than the 12 h warn threshold"
          ]
        ]
      }
    }
  ]
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

## Run it on a schedule

Suggested: Every day at 7:30 (`30 7 * * *`). From cron, with the agent signed in on that machine:

```bash
30 7 * * * claude -p "Run the dbt-failed-runs-and-stale-sources skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/dbt-failed-runs-and-stale-sources#schedule

Source: https://briefkin.dev/skills/dbt-failed-runs-and-stale-sources
