# If It Doesn't Work

> sparku doctor, typical errors — from missing socket to 409, request log and "Test" console.

## Start with `sparku doctor`

```bash
sparku doctor
sparku doctor deploy   # plus check token and schema for a specific integration
```

Steps through and prints `✓`/`✗` on each: socket, `/v1/health`, CLI version against
app version, and with an integration address — the token source and its fields.
Stops on the first problem and returns the corresponding exit code
([sparku CLI](/docs/api/cli.md#exit-codes)).

```
sparku 2.4.0
✓ socket: /Users/you/.sparku/run/api.sock
✓ SparkU 2.4.0, API v1
✓ token for "deploy": $SPARKU_TOKEN_DEPLOY
✓ integration "Deploy": progress (progress), stage (state), title (text)
```

## Socket doesn't exist

```
✗ socket doesn't exist: /Users/you/.sparku/run/api.sock
```

One of two things:

- **SparkU is not running.** Start the app.
- **"Custom Integrations" is disabled.** Settings → Integrations → Custom Integrations →
  "Enable…". The feature is experimental and disabled by default (see
  [Overview](/docs/api/overview.md)).

Any request to a missing socket — code `69` (`sparku`) or a connection error
(`curl: (7) Failed to connect`, `ConnectionRefusedError` in Python). A script can reliably tell
"SparkU not running" from other errors: unavailability is checked first, before token and address.

## 401 — missing or wrong token

```json
{"error": {"code": "unauthorized", "message": "token required: Authorization: Bearer <token> header (SparkU Settings → Custom Integrations → Connection)"}}
{"error": {"code": "invalid_token", "message": "token doesn't belong to integration \"deploy\" — it may have been reissued"}}
```

- `unauthorized` — no `Authorization` header at all. In `sparku` this means the token was not found in
  `--token`, `--token-file`, `SPARKU_TOKEN_<ADDRESS>`, or `SPARKU_TOKEN` (lookup order —
  [sparku CLI](/docs/api/cli.md#token)).
- `invalid_token` — token exists but doesn't match: typo, wrong token, or it was reissued in Settings
  (for example after a suspected leak). Get the current token there: `slug` → Connection.

`sparku` exits with `77` in both cases.

## 404 — integration doesn't exist

```json
{"error": {"code": "unknown_integration", "message": "integration \"deploy\" doesn't exist; create it in SparkU Settings → Custom Integrations"}}
```

Typo in the address or the integration hasn't been created by the user yet — the API never
creates integrations itself ([Concepts](/docs/api/concepts.md)). `sparku` — code `67`.

## 422 — value failed validation

```json
{"error": {"code": "invalid_fields", "message": "progress: expected 0…1, got 70",
 "fields": [{"field": "progress", "message": "progress: expected 0…1, got 70"}]}}
```

The error text is readable in the terminal as-is — which field and what's wrong with it. Write is
**all or nothing**: if any field in the request fails validation, none are applied, even if others
were correct. Check the field's type and range against the schema — `GET /v1/integrations/{slug}` or
the "Fields" section in the editor. `sparku` — code `65`.

## 429 — `notify` too frequent

```json
{"error": {"code": "too_many_notices", "message": "notify no more than once per 2s"}}
```

The response header `Retry-After` says how long to wait. This is not a data error — the limit
protects against a "strobe" if `notify` runs in a loop. `sparku` — code `75`; a script can catch
just `75` to tell frequent `notify` apart from other issues.

## 409 — state conflict

| Code | Reason | Fix |
|---|---|---|
| `integration_disabled` | integration is disabled in Settings | enable it in Custom Integrations |
| `notify_disabled` | `notify` is disabled in this integration's settings | enable in the "Island" section of the editor |
| `dialog_pending` | integration already has an unanswered question | wait for the answer or withdrawal |
| `import_pending` | SparkU is already offering another import to the user | wait for its answer |

All these codes are temporary state, not a request error: `sparku` returns `69`
("SparkU unavailable") for the first two and the same for the rest — see the code table in
[HTTP API](/docs/api/http.md#error-codes).

## Integration request log

Settings → Custom Integrations → `slug` → "Log" section — the last 50 requests to
this integration: action (`push`/`end`/`notify`/`ask`/`listen`/`describe`), response code,
error text or user answer, and the client process (`python3`, `curl`, etc. by PID on the
socket). This is the first place to look when a script "seems to be sending something" but
nothing changes on the island: the log shows whether a request arrived and what the server
responded, without needing to debug the script.

## "Test" console in the editor

In the integration editor (the "Test" section), you can send values the same way `push` does,
clear them, call `notify`, and ask a test question — all without leaving the terminal. Useful
to separate "card is misconfigured" from "script is sending wrong data": if values from the
console display on the island correctly but values from the script don't, the problem is in
the script (address, token, field names, JSON format), not the integration itself.

## Other issues

- **Expired values.** If `GET /v1/integrations/{slug}` shows an empty
  `values` but you definitely wrote values — check `expires_at` from the previous response:
  the TTL (integration's `valueLifetime` or `?ttl=`) expired. `push` is upsert; the next
  write will restore them.
- **CLI and app version mismatch.** `sparku doctor` prints a warning
  if `sparku` in `/usr/local/bin` links to a different copy of SparkU than the one running.
  Refresh the symlink: Settings → Custom Integrations → "Command line".
- **`sparku listen` gets no events.** While the stream is not open, elements with "send event
  to listener" action are inactive on the island itself — a tap doesn't go anywhere, no event
  fires at all. Open `listen` first, then tap the button; see [Buttons and Events](/docs/api/events.md).
