---
title: Troubleshooting
description: The 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-09-11
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.ai/app/schedules](https://dashies.ai/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 dashboard bound to a data source from a different workspace.** 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 Suspended

Dashies stopped scheduling it. This is not another way of saying Failing: it
means the retries have stopped too, so waiting will not help.

It happens when a dashboard fails enough consecutive **scheduled** runs, for a
cause you can fix, over at least a week. One message was sent when it happened:

```text
Refresh suspended: <slug>
```

Fix the cause first, then start it again. A refresh that succeeds turns the
schedule back on by itself, so **Run now** is usually the whole fix. If you would
rather clear the state without running anything, use **Resume schedule** on the
row menu, on the dashboard's schedule page, or on the Issues page. Full rule and
every way back:
[Suspended schedules](/operate/failure-alerts#suspended-schedules).

### 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 in the workspace goes quiet at the same time**, because they
all key on the same plan - the workspace's. If several of your team's dashboards
went stale together, check the workspace's own subscription. It is not any one
member's plan you are looking for. 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, and the payer is the workspace the dashboard lives in:

```text
Refreshing on demand requires a paid plan on this workspace. Only a workspace admin can change the plan.
```

:::warning{title="A plan on another workspace does not clear this"}
The plan checked is **this workspace's**, not one held by another workspace you belong to and
not the one held by whoever created the data source. Putting a paid plan on **this workspace**
is what clears it.

Only a workspace admin can do that, so if you are not one, ask an admin rather
than buying anything yourself. The refusal renders a **View plans** button
regardless of whether you are an admin; which control a non-admin should be
offered here is tracked as #832.
:::

From an AI tool there is a second reason, unrelated to plans - refreshing a
workspace dashboard rewrites its data, so it takes the same permission as
republishing it:

```text
You hold a view-only role in this workspace, so you cannot publish, change or refresh its dashboards. A workspace admin can change your role.
```

Ask a colleague who can publish to the workspace, or to change your role. **Run
now** in the web app applies the same rule, so switching to it will not help - it
just words the refusal for a browser (`your role in this workspace is
view-only`).
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 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.

Your AI can read the same thing:
[`get_source_config`](/reference/mcp-tools/get-source-config) returns the compiled
manifest, and any member of the workspace may read it.

### 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
```

**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
```

**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
```

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

## 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).

## Why did I not get an alert?

Something broke, the Schedules page agrees, and nothing arrived. Work down this
list: each step rules out one layer, and the run's own page settles it at the end.

### 1. Was a message even owed?

An alert fires on the **threshold**, not on the first failure, and the default is
three consecutive failures. Check Settings, then Alerts. A dashboard that failed
twice is behaving exactly as configured.

A **muted** dashboard sends nothing about failures at all. Its Schedules row
carries a struck-through bell. The one exception is a suspension notice, which is
sent whatever the mute says.

On a **free plan** nothing is sent, on either channel.

### 2. Is the category switched off?

A workspace admin can switch off a whole family per channel under Settings, then
**Notifications**. A refresh failure is in **Refresh failures**; a failure on our
side is in **Platform incidents**, which is a different row, so switching one off
does not silence the other.

**Workspace security** only exists on Enterprise. On any other plan the row is
absent rather than off.

### 3. Is your own email switched off?

Under Settings, then Alerts, **My channels** carries one switch,
`Email me about my dashboards`. It is the last word: turning it off stops every
alert email to you whatever a workspace admin has set. If it is off, the pane
says when:

```text
Alert emails are off. You turned them off on 2026-09-01, here or from the unsubscribe link in an alert email. Switching this back on undoes that.
```

**It does not say which of the two turned it off, deliberately.** The switch on
this pane and the unsubscribe link in an email write the same thing, and nothing
records which one it was. Switching it back on undoes either.

### 4. Was the daily limit already spent?

**Ten messages per recipient per 24 hours**, counted across **Refresh failures**
and **Platform incidents** together. Past that, further messages in those two
categories are recorded rather than sent. Open the run's permalink and look for
the chip:

```text
Email not sent, daily limit reached
```

Every other category is exempt, so a suspension notice or a billing notice still
arrives on a day the limit is spent.

### 5. Did the send fail?

Open the run's permalink. Each alert line carries one chip per delivery, and the
chip says what happened: `Email delivered`, `Email queued`, `Email failed`,
`Slack failed, no more attempts`. A failed send is retried on a widening ladder
for up to six attempts, so `queued` and `failed` both still have a future.

See
[what was sent about a run](/operate/monitor-refreshes#what-was-sent-about-a-run-and-whether-it-arrived).

### Nothing arrives in Slack

Four different things, and the pane distinguishes them:

| The card says | What it means |
|---|---|
| `Not connected. Alerts for this workspace go to email only.` | No install. Press **Add to Slack**. |
| `Connected, but alerts have nowhere to post.` with an amber `No channel` pill | Installed with no destination. Press **Pick a channel**. |
| `Dashies cannot post to Slack right now.` with a red `broken` pill | Slack refused. See below. |
| The Slack column in the matrix is off | The category is switched off for Slack even though the channel is fine. |

A **broken** card names the reason Slack gave, and there are two shapes of fix.
If the app was removed from Slack or the token revoked, press **Reconnect to
Slack** and go through the Allow screen again. If the channel was archived or
deleted, the install is fine and **Change channel** is the fix. Nothing is lost
in the meantime: a message that cannot be posted is retried, and the run page
records every attempt.

Full walkthrough: [Slack alerts](/operate/slack-alerts).

## 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.
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.
