Home / Data Platform / Governance

Data PlatformRunbookBeginner

\"The dashboard has no data for today\" - a triage runbook for late or missing data across the pipeline

When a report shows stale or missing data, work backwards from the report through the semantic model, warehouse tables, pipelines and source. Find the first layer where the data stops, fix it, backfill and tell users.

Deepak Bhardwaj5 min read

Applies toAny batch or streaming data platform (Databricks, Snowflake, Synapse/Fabric, BigQuery) with an orchestrator (Airflow, ADF, Workflows) and BI tools such as Power BI or Tableau

The approach

Data flows source → ingestion → raw/bronze → transformations → serving tables → semantic model → report. Start at the report and walk backwards until you find the first layer where today's data is present. The problem is in the layer just after that one.

Write the timeline in the incident channel as you go. It saves time later.

Step 1: confirm the symptom (5 minutes)

  • Which report, which page, which filter? Is it missing, partial or wrong?
  • Is it all users, or one region or role? Row-level security can make data look missing.
  • When did it last look right?

Step 2: the report and semantic model

  • Check the dataset refresh history. In Power BI, the semantic model's Refresh history shows failed or skipped refreshes.
  • If the refresh succeeded, but before upstream data landed, the fix is simply to refresh again and change the schedule.
# Power BI: last refreshes for a dataset (MicrosoftPowerBIMgmt module)
Invoke-PowerBIRestMethod -Method Get -Url "groups/<workspace-id>/datasets/<dataset-id>/refreshes?`$top=5" |
  ConvertFrom-Json | Select-Object -ExpandProperty value | Select status, startTime, endTime, serviceExceptionJson

Step 3: serving tables

Check the freshness of the tables the model reads:

SELECT max(load_ts) AS last_load, max(business_date) AS last_business_date, count(*) AS rows_today
FROM gold.sales_daily
WHERE business_date = current_date - 1;

Compare the row count with the same day last week. A count of zero, or a sharp drop, tells you whether the data is missing or partial.

On Delta tables you can see when the table was last written and by which job:

DESCRIBE HISTORY gold.sales_daily LIMIT 5;

Step 4: pipelines

In the orchestrator, find the jobs that build those tables:

Finding Meaning
Job failed Read the error; fix it and rerun
Job succeeded but wrote 0 rows Upstream was empty or late when it ran
Job didn't run Schedule paused, trigger stopped, upstream dependency never completed
Job still running Slow; check resources, skew and locks
# Airflow
airflow dags list-runs -d sales_daily --state failed -o table
# Databricks
databricks jobs list-runs --job-id 123 --limit 5 --output json | jq '.runs[] | {run_id, state}'

Step 5: raw/bronze and the source

SELECT max(_ingested_at), count(*) FROM bronze.sales_orders WHERE _ingested_at >= current_date;
  • Nothing in bronze means ingestion or the source is the problem. Check the ingestion job, landing folder, CDC connector lag or API errors.
  • Check the source directly: did the source system send a file today? Was there an upstream outage, a schema change or a credential expiry?

Common root causes

Cause Typical clue
Upstream file late or missing Landing folder empty; source team confirms delay
Expired credential or secret 401/403 errors in ingestion
Schema change at source Parse errors, NULL columns, rows rejected
Job ran before upstream finished Success with 0 rows; time-based schedule instead of dependency
Capacity or quota Jobs queued, warehouse suspended or throttled
Report refreshed too early Data present in tables but not in the report
Filter or RLS change Data present for some users only

Step 6: fix, backfill, verify

  1. Fix the cause (rerun, update the credential, adjust the schema).
  2. Backfill the affected dates in dependency order, from bronze through gold to the semantic model.
  3. Verify counts and totals against the source or the same day last week.
  4. Refresh the report and check it as a user would.

Warning

Make sure reruns are idempotent (overwrite the partition or merge on keys). Appending a second load doubles the numbers, which is worse than missing data.

Step 7: communicate

Post a short update when you confirm the issue and when it's fixed:

Sales dashboard missing 25 Oct data. Cause: supplier file arrived 3 hours late. Data loaded and verified at 10:40; dashboard refreshed. Next step: switch the load to trigger on file arrival.

Prevent it next time

  • Freshness checks on key tables (for example dbt source freshness or a scheduled query) that alert before users notice.
  • Volume checks comparing row counts with the recent average.
  • Dependency-based triggers (file arrival, upstream job success) instead of fixed times.
  • Show "data as of" on dashboards so users can see staleness themselves.
  • An owner per dataset and an agreed delivery time (data SLA).

Checklist

  • Symptom confirmed (missing, partial, wrong; who's affected)
  • Walked back layer by layer to the first missing layer
  • Root cause fixed
  • Backfill in dependency order, idempotent
  • Counts verified and report refreshed
  • Users updated
  • Freshness/volume alert added