Data Quality

How to Diagnose a Dashboard That Looks Wrong

A senior analyst’s triage playbook for the Monday morning Slack: "the number on the dashboard doesn’t match Finance — can you check?"

8 min read

A stakeholder pings you Monday at 9:47 AM: "The revenue number on the exec dashboard says $4.2M, but Finance closed the quarter at $4.7M. Can you take a look?" You now have 30 minutes before the exec meeting. This post is the triage playbook — the order of checks to run, from highest-likelihood/lowest-cost to lowest-likelihood/highest-cost, so you find the bug (or confirm the number) in the time you actually have.

The Slack message that starts the fire

The wrong move is to immediately open the dashboard and start drilling in. The right move is to get two more pieces of information from the stakeholder before you query anything:

  • Their reference number and its source. "$4.7M from Finance" means what system? The GL? A board deck? A spreadsheet that Finance hand-maintains? The discrepancy often lives in the reference, not the dashboard.
  • The exact scope. "Quarter revenue" — which quarter, which entity, which revenue definition (gross, net, recognized, booked)? One of the first three checks is whether you’re even comparing the same thing.

Triage, not investigation

Triage and investigation are different jobs. Triage is ordered by cheap-to-expensive; investigation is ordered by "let’s understand this thoroughly." In the first 30 minutes you’re doing triage: quickly rule out the common causes and isolate where the bug lives, not fully fix it. Investigation happens after you’ve shipped an interim answer.

The senior-analyst move is to return something to the stakeholder before the meeting: "The gap is in the timezone handling on the close, not the dashboard logic — dashboard is right, Finance’s number is using a different cutoff. I’ll send a full writeup this afternoon." That’s triage. The full writeup is the investigation that comes after.

The seven checks, in order

Run these in order. The first one that finds a gap is usually the cause. Each takes 2–5 minutes; if you’ve run all seven and the gap persists, you’re in real-investigation territory.

1. Are you comparing the same metric?

Gross revenue includes refunds; net revenue subtracts them. Booked revenue is when the deal closed; recognized revenue is when the period earns it. A $500k gap on a $4.5M base is exactly the size of the difference between "booked" and "recognized" for a SaaS company in their second quarter. Check this first.

2. Are you comparing the same window?

Finance closes on the last business day; the dashboard may include the weekend. Finance uses fiscal quarters starting February; the dashboard uses calendar quarters. The timezone on the purchased_at column is UTC; Finance’s working calendar is local. All of these produce discrepancies that look like bugs and are actually definition gaps.

3. Are you comparing the same entity set?

The dashboard may be scoped to "active customers;" Finance may include churned ones. The dashboard may be scoped to one subsidiary; Finance may consolidate all entities. If the stakeholder’s reference is a consolidated number and your dashboard is a single-entity view, you’ll never match.

4. Has the source data changed since the number was computed?

Backfills, corrections, and late-arriving data are common. The dashboard pulled a snapshot at 7 AM; a backfill job ran at 9 AM; Finance’s number is based on the post-backfill state. Re-run the dashboard’s query now and compare to its cached value. If they differ, staleness is the cause — the dashboard is correct in its window, just behind.

5. Is there a known JOIN fanout in the dashboard query?

Pull the query that powers the dashboard tile. Look for joins on nullable or many-sided columns. Run the component queries unjoined and count rows; run the joined query and count rows. If the joined count is much bigger than expected, you’ve found the bug — revenue is being multiplied by memberships or tags. This is the single most common root cause of wrong-number dashboards.

6. Is the filter doing what it says?

Check NOT IN against a nullable column (see anti-joins post for why this silently breaks). Check that WHERE status = 'active' matches the casing of the actual values. Check that a date filter is using the correct column (authored_at vs published_at).

7. Is the BI layer doing something unexpected?

Last, because it’s rarest: the BI tool may be re-aggregating, applying a user-level filter, or using a cached extract that’s not what the SQL says. If you’ve run the raw SQL from the BI tool’s query-log and gotten the dashboard’s number, the bug is in the data, not the BI layer. If the raw SQL produces a different number than the dashboard, the bug is in the BI layer.

Reporting back without losing credibility

However the triage goes, the stakeholder needs a response before the 10:15 meeting. Three templates, pick the one that matches what you found:

Template A: The dashboard is right

Dashboard is correct for its scope. The $500k gap to Finance’s number
is because Finance is reporting recognized revenue (GAAP), and the
dashboard is reporting booked revenue (CRM). Both are "right" — they’re
different metrics.

If you want recognized revenue on the dashboard, I can add a tile this
week. Otherwise the cleanest fix is a footnote clarifying which one
this tile shows.

Template B: The dashboard is wrong, you know why

Dashboard is wrong. The revenue query is double-counting orders that
have multiple line items — the JOIN to order_items is fanning out.
Inflating the Q1 total by ~8%.

Temporary fix: I’ve noted the issue on the tile. Permanent fix: I’ll
roll up order_items to one row per order before the JOIN and push
the corrected version this afternoon.

Template C: You’re not sure yet

Initial check suggests the gap is in the timezone handling on the
quarter-close cutoff, not in the dashboard query itself — but I want
to verify before the meeting. Can we hold the discussion on the tile
until I confirm? I’ll have an answer by noon.

The template-C move is the most underrated. Experienced analysts don’t pretend to know what they don’t know — they triage, communicate their confidence honestly, and buy the time to be right. That’s the trait that makes a stakeholder trust the next dashboard number you hand them, even when it disagrees with a reference.

Build these reflexes against real data.

caseSQL runs 100+ missions against a realistic star schema with planted data-quality issues. Free tier runs in your browser; upgrade to Pro for interview prompts.

Keep reading