## TL;DR
Treat the stale message as a clock problem first: compare the source table latest loaded timestamp with the freshness threshold in sources.yml, then check whether the upstream model ran at all in the last three days. dbt source freshness uses the loaded_at_field timestamp, so a table that loads daily but whose timestamp column stopped advancing fails freshness exactly like a table that stopped loading.

```text
dbt source freshness failed error "sources.freshness stale: last loaded 3 days ago"
```

## Use this when
- The check or run fails with this symptom: dbt source freshness reports stale with last loaded 3 days ago.
- You are working on a dbt project whose source freshness check fails on a table that should load daily and the failure repeats on the same data or configuration.
- You need the failing rows, rule, or stage isolated before changing thresholds or code.

## Not for this skill when
- A source that is intentionally loaded weekly, where the threshold in sources.yml is wrong rather than the pipeline.
- The error text names a different tool, stage, or root cause. Match the verbatim error first and use that skill.

## Steps
1. Read the freshness block for the source in sources.yml and note warn_after and error_after plus the loaded_at_field column. Verify: the configured threshold and timestamp column are known
2. Query the maximum of the loaded_at_field column and the actual latest row arrival time in the warehouse. Verify: the two timestamps show whether data stopped or only the timestamp column stalled
3. Check the upstream job runs for the last three days. Verify: a missing or failed upstream run is confirmed or ruled out
4. Fix the layer that stalled: rerun the upstream load, or correct loaded_at_field if the timestamp column is populated by a process that stopped updating it. Verify: freshness passes on the next dbt source freshness run
5. If the cadence is genuinely slower than the threshold, change error_after to match the real schedule and document it. Verify: the threshold now reflects the agreed load cadence

## Variant phrasings
### dbt source freshness stale last loaded 3 days ago
The shorter phrasing focused on the named failure.
### sources.freshness stale error dbt
The symptom phrasing a searcher tries next.
### dbt source freshness failed how to debug
The variant naming the failing stage or tool directly.

Compatibility: dbt Core 1.5 and later and dbt Cloud source freshness

## Why it happens
Freshness is measured from one timestamp column, not from job success. Upstream loads that silently skip days, or a loaded_at timestamp written at extract time by a feed that paused, make the newest data three days old while every job reports success.

## Edge cases / pitfalls
- Do not just raise error_after to make the alert stop; that converts a real missed load into an invisible one.
- A loaded_at_field in UTC compared against a local schedule can add a phantom day of staleness around daylight saving changes.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_8DeCk51kioVthsBI1UrHaw
