---
title: Troubleshooting
description: Four questions people actually ask about a dashboard that stopped working, each answered as a procedure with the exact text Dashies puts on the screen.
updated: 2026-08-05
tier: free
---

Each section below starts from what you can see and narrows to one cause. Where
Dashies prints a message, it is quoted here exactly, so you can search for the
sentence you are looking at.

## Why did it not refresh?

Start on [dashies.xyz/app/schedules](https://dashies.xyz/app/schedules) and find
the dashboard. Where it is on that page is most of the answer.

### It is not listed at all

Only dashboards with a connected data source appear. If yours is absent it has no
refresh manifest, so there is nothing to re-run. The page says so in its empty
state:

```text
Dashboards become schedulable once they have a connected data source. Connect one in Data sources, or publish a data-backed dashboard from your AI tool, then set its cadence here.
```

Three ways a dashboard ends up here:

1. **It was published as plain HTML.** A dashboard published without a spec and a
   source is static by design. Republish it through your AI tool with a spec. See
   [Author a dashboard](/guides/author-a-dashboard).
2. **The publish succeeded but the refresh manifest did not install.** The
   dashboard is live at a real URL and stays static until it is republished. Your
   AI tool was told:

   ```text
   dashboard content was saved, but refresh installation failed - call get_dashboard_spec and republish with the returned spec_hash to complete.
   ```

3. **It is a workspace dashboard bound to a personal data source.** This is the
   most expensive version, because everything upstream succeeds. Read
   [the workspace trap](/concepts/connections-and-scope#the-workspace-trap), which
   is the whole story and the fix.

:::danger{title="A dry run does not catch case 3"}
`dry_run` stops before the manifest is installed, so a clean dry run is not
evidence that the data source can be bound in the scope you are publishing into.
:::

### It reads Not scheduled

The cadence is `manual`, so it runs only when someone triggers it. Give it a
cadence: [Set and change a refresh schedule](/guides/refresh-schedule).

### It reads Paused - plan lapsed

Runs are being **skipped**, not failed. Nothing is broken and nothing was
deleted. The schedule is preserved and the next due run after an upgrade
refreshes normally. See
[what a lapsed plan actually does](/concepts/plans-and-gating#what-a-lapsed-plan-actually-does).

### It reads Paused or Archived

Someone set it that way. Pausing is also how you stop retries on a dashboard you
know is broken.

### It reads Failing

A run happened and it failed, so the dashboard is serving its last good numbers.
Open **History**, select the dashboard, and read the reason on the newest run.
The classified reasons and what each means are in
[what a failed run tells you](/operate/monitor-refreshes#what-a-failed-run-tells-you).

It is already retrying. The **Next run** column shows when.

### It reads Stale, with no failed run

Nothing errored and nothing ran. Check the scheduler caption above the tabs
first:

- **Scheduler active** means the engine is running and this dashboard was
  missed. If it stays missed you get an email, subject `Refresh overdue:`.
- **Scheduler may be delayed** means the engine itself is behind, and no
  dashboard is refreshing. Nothing you change on this dashboard will help.

There is one more shape worth knowing, because it looks perfectly healthy: a next
run set so far ahead that it will never fire. Dashies detects it and emails
`Refresh not scheduled:`. Setting the schedule again fixes it.

:::danger{title="On a team dashboard, check this before anything else"}
**A workspace dashboard never shows Paused - plan lapsed.** That verdict is
computed from the plan of whoever is looking at the page, and on a team dashboard
the plan that actually pays is the data source creator's. So a team dashboard
whose data source owner has lapsed reads **Stale**, with no failed run and no
indication anywhere that a plan is involved.

Where the real cause is visible depends on who you are:

- **If you published the dashboard**, its run history shows the due runs as
  **Paused**, carrying a lapsed tier. That is the answer.
- **If a colleague published it**, the History tab shows you nothing: it reads
  the run log directly, and that is readable only by whoever published the
  dashboard. Ask your AI for the dashboard's refresh status instead.
  [`get_refresh_status`](/reference/mcp-tools/get-refresh-status) is
  workspace-capable and returns the recent runs to any member, so the paused runs
  are visible there even though the page shows none.

So the tell has to be the pattern rather than any one dashboard: **every
scheduled dashboard on that data source goes quiet at the same time**, because
they all key on the same person's plan. If several of your team's dashboards went
stale together, find who created the data source they share and check whether
their plan is still active. See
[whose plan is checked](/concepts/connections-and-scope#whose-plan-is-checked).
:::

### It reads Up to date but the numbers look old

Two possibilities, and the run history separates them:

- The newest run is marked **No change**. The SQL re-ran and produced identical
  data. Your source data has not moved, or your query's time window is not
  relative to now.
- The newest run succeeded with a row count. It refreshed, and what you are
  looking at is what your warehouse returned. Go to
  [Why are the numbers wrong?](/operate/troubleshooting#why-are-the-numbers-wrong)

### It is a few minutes past its next run

That is normal, not late. Runs are claimed on a grid and each dashboard carries a
small fixed offset, so an anchored schedule fires within roughly 30 minutes of
its displayed time. See
[the precision you actually get](/concepts/schedules#the-precision-you-actually-get).

## Why can I not refresh it on demand?

**Run now** on the Schedules page, and `trigger_refresh` from your AI tool, are
both paid. What differs is who has to be paying.

| Dashboard | Message |
|---|---|
| Personal | `Refreshing on demand requires a paid plan.` |
| Workspace | `This dashboard's data source is on a plan that no longer includes refresh. The member who connected it needs an active paid plan.` |

:::danger{title="On a workspace dashboard, upgrading your own plan does not clear it"}
The plan checked is the one belonging to whoever **created the data source**,
which may be someone else entirely. The refusal currently renders a **View
plans** button, and that button takes you to **your** plan, not theirs. Following
it and upgrading will not make the refusal go away.

The fix is to find the member who created that data source and have them
resubscribe, or to bind the dashboard to a data source created by someone whose
plan is active. This is a known defect in the button, tracked as #832.
:::

From an AI tool there is a second reason, unrelated to plans:

```text
Triggering a refresh on demand isn't available for workspace dashboards yet - it works on personal dashboards only.
```

Use **Run now** in the web app for a workspace dashboard. Scheduled refresh of a
workspace dashboard works normally, and so does reading its status. Every
`trigger_refresh` refusal is listed on its
[reference page](/reference/mcp-tools/trigger-refresh#errors).

One more that reads like a failure and is not: a repeat trigger within 60 seconds
of a previous attempt is coalesced and reports back as such, **unless the last
attempt failed**. A retry seconds after a failure genuinely re-runs.

:::note{title="These three messages are quoted in more than one place"}
The same text appears on
[Set and change a refresh schedule](/guides/refresh-schedule#running-one-now)
and, for the tool refusals, on the
[`trigger_refresh` reference](/reference/mcp-tools/trigger-refresh#errors). They
are quoted from the server rather than described, so if the message on your
screen matches none of them, you are on a newer build than this page.
:::


## Why are the numbers wrong?

First separate **wrong** from **old**, because they have nothing in common.

:::steps

### 1. Check when it last succeeded

Open **History** and select the dashboard. The freshness line says
`Updated 12m ago`, or `Last run failed 40m ago`, or `Refresh paused`. If the last
success is old, the numbers are not wrong, they are frozen. Go back to
[Why did it not refresh?](/operate/troubleshooting#why-did-it-not-refresh)

### 2. Look at what the run actually wrote

Click **View** on the newest successful run. That opens the data that run
produced, exactly as it was stored. Compare two runs to see what moved.

### 3. Look at the query

**View query** on the Schedules row shows the SQL the refresh runs. This is the
statement that produced the numbers, not a reconstruction of it.

On a **workspace** dashboard that control is not there. Ask your AI for the
dashboard's source config instead, which returns the same compiled manifest and
is readable by any member. See
[View query is personal dashboards only](/operate/monitor-refreshes#seeing-what-a-run-produced).

### 4. Cross-check one measure against your warehouse

Run the independent aggregate yourself and compare. The procedure is
[Verify your numbers](/guides/verify-your-numbers), and it is the only step that
can actually establish the numbers are right.

:::

Once you know it is genuinely wrong rather than old, the cause is almost always
one of these:

| What you see | Likely cause |
|---|---|
| A total far larger than it should be | A non-additive measure being summed. [Measure correctness](/concepts/measure-correctness) |
| A total that is close but not equal | A join fanning out and double counting. [Measure correctness](/concepts/measure-correctness#what-no-check-can-do-for-you) |
| Numbers that are exact but for the wrong period | The time window in the SQL is absolute rather than relative to now |
| A filtered view disagreeing with the unfiltered one | The dataset mode cannot answer that filter exactly. [Datasets and the four modes](/concepts/dataset-modes) |

### Tiles are blank, or show dashes

That is a different failure from a wrong number, and it usually means the data
arrived but could not be read. Look for this reason on the newest run:

```text
island_unaddressable: the refreshed data is present but 3 declared keys would not resolve in it - main.month, main.ending_arr, main.__g_month. The previous data was kept. This usually means the statement's output column names no longer match the declared keys.
```

The refresh fetched real rows and then refused to publish them, keeping your
previous data. It follows a change to the column names your statement returns.
Republishing the spec re-derives the declarations against the current statement.

A single value rendered as `-` is a different thing again and is working as
intended: the runtime shows a dash rather than a number it cannot render
exactly. It never rounds a value into a wrong one.

## Why can I not schedule it?

The Schedules page accepts the cadence, then the save fails with a message. Each
one names the constraint.

**The plan gate.** Any cadence other than manual needs a paid plan:

```text
a paid plan is required to schedule automatic refresh
```

Setting a schedule **back to manual is always allowed**, on any plan.

**No data source.** The dashboard has nothing to re-run:

```text
this dashboard has no connected data source, so it cannot be scheduled to refresh; publish it with a data source via your AI tool first
```

**Sub-hourly on a team dashboard.** Not supported yet:

```text
sub-hourly refresh is not supported on workspace dashboards yet
```

**Permissions.** You are not the owner, or not a member:

```text
not authorized for this dashboard
not a member of this workspace
```

**Interval out of range.** Each cadence has its own allowed intervals:

```text
an hourly interval must be every 1, 2, 3, 4, 6, 8, or 12 hours
a daily interval must be between every 1 and every 30 days
a weekly interval must be between every 1 and every 4 weeks
a monthly interval must be between every 1 and every 12 months
a sub-hourly interval must be every 15 or 30 minutes
```

**Anchor out of range, or the wrong anchor for the cadence.** The anchor fields
differ per cadence, and supplying one that does not apply is refused rather than
ignored:

```text
hour must be between 0 and 23
day-of-week must be between 0 (Sunday) and 6 (Saturday)
day-of-month must be between 1 and 28
timezone must be a valid IANA timezone name
an hourly schedule does not take a day-of-week or day-of-month
a daily schedule does not take a day-of-week or day-of-month
a weekly schedule does not take a day-of-month
a monthly schedule does not take a day-of-week
a weekly schedule needs both a day-of-week and an hour
a monthly schedule needs both a day-of-month and an hour
a sub-hourly schedule does not take a day, time, or timezone
```

Why each limit exists is in
[cadences and intervals](/concepts/schedules#cadences-and-intervals).

### My AI tool cannot set the schedule I want

`set_refresh_schedule` takes no sub-hour argument, so an AI cannot set every 15
or 30 minutes however confidently it offers to. Use the Schedules page. Full
argument list on the
[tool reference](/reference/mcp-tools/set-refresh-schedule).

## Why does it say connected but failing?

Because those are answers to two different questions, and both are true.

- **Active** is what an explicit **Test** concluded. That test may be days old.
- **failing** is what real refreshes have observed since.

The newer news is the health reading. The model, including why it takes two
consecutive observations to flip and why timeouts are excluded, is on
[status and health are two different facts](/concepts/connections-and-scope#status-and-health-are-two-different-facts).

What you see on the data source card is the green **Active** pill with an amber
note underneath. The note is phrased as an event, not a verdict, and it names the
candidates worth checking rather than asserting one:

```text
The last refresh of this data source was not authorized by the warehouse. Check its credentials and account access. It clears once a refresh succeeds.
```

```text
The last refresh of this data source could not open a secure connection to the warehouse. Check the warehouse's TLS settings. It clears once a refresh succeeds.
```

```text
The last refresh of this data source did not get a usable response from the warehouse. Check that the warehouse is reachable and not over its query limits. It clears once a refresh succeeds.
```

When the observation came from authoring rather than a scheduled refresh, the
first clause reads `The last request Dashies made to this data source` and the
last reads `It clears once this data source is used successfully again.`

### What to do about it

:::steps

### 1. Decide whether it still matters

Health records a past observation. If refreshes have succeeded since, the note is
already gone. Check the dashboard's run history before changing any credential.

### 2. Read what the note actually names

`not authorized` covers a rejected credential **and** an account or billing
problem on the warehouse side. `did not get a usable response` covers an
unreachable host **and** being over a query quota. Rotating a working credential
because of a quota problem is the mistake this wording exists to prevent.

### 3. Fix the cause, or test the data source

A passing **Test** clears the note immediately, including on a data source with
no dashboards left on it. A failing Test sets the card to **Error** and leaves
the health note alone.

:::

Two things this reading does **not** mean:

- **It does not block anything.** Health gates nothing. Refreshes, authoring and
  publishing all proceed exactly as they would without it.
- **It is not the same as the Error pill.** **Error** means the last Test failed.
  **Active** with an amber note means the last Test passed and a real refresh
  since then did not.

Your AI tool sees the same pair. `list_connections` returns `status` and
`health_state` as separate fields, described on its
[reference page](/reference/mcp-tools/list-connections).

## Check it worked

Whatever you changed, confirm it the same way:

1. Trigger a run. Use **Run now** on the Schedules page, or ask your AI to
   trigger a refresh of a personal dashboard.
2. Open **History** and select the dashboard. A new run should appear at the top
   with a **Succeeded** status and a row count.
3. The dashboard's verdict should now read **Up to date**, and its freshness line
   `Updated just now`.
4. If you fixed a data source, its card should show **Active** with no amber
   note.
5. If an outage was open, a `Refresh recovered:` email arrives on the run that
   closes it.
