> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trycurious.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# The SDK keeps serving the fallback

> result.served is fallback: read error.code to tell a timeout from a wrong key, an undeclared element, a shape mismatch or an outage, and what fixes each.

`decide()` returns `served: "fallback"`. Users see your control, which is correct behaviour; the cause is in `result.error.code`.

| `error.code` | Cause | Fix |
| - | - | - |
| `timeout` | The deadline (`decideTimeoutMs`, 1.5 s by default) passed. Common on a cold runtime or a slow network path. | Confirm the deadline fits your budget. Construct one client per process so connections are reused. Decide server-side where the network is predictable. |
| `authentication_error` | `401`: the key is missing, wrong or revoked. | Check `CURIOUS_SECRET_KEY` in this environment. After a rotation, deploy the new key before revoking the old. |
| `invalid_key_type` | A publishable key was given to the server SDK. | Use a secret key on servers. |
| `undeclared_element` | `409`: the element has no live experiment. | Declare it with a secret key first ([`declare`](https://docs.trycurious.ai/guides/declare)) or send a `declaration` on this call. |
| `invalid_input` | `400`: a field is wrong; `error.message` names it. | Fix the field. Declaration fields are camelCase in the SDK and converted for you. |
| `content_shape_mismatch` | The response's content does not have the fallback's shape. | Align the fallback with the control: a string control needs a string fallback, an object control an object with the same fields. A format change restarts the experiment, so check the declaration too. |
| `rate_limited` | `429`. | Batch events; find the loop. See [Rate limits](https://docs.trycurious.ai/api-reference/rate-limits.md). |
| `network_error`, `server_error` | No response, or a `5xx`. | Nothing on your side. Watch the fallback rate; quote `requestId` to [support](mailto:team@trycurious.ai) if it persists. |
| `protocol_error` | A non-JSON error, `404` or `405`. | Check `baseUrl`; the default is `https://api.trycurious.ai/v1`. |

## Every call times out

If every decision is `timeout` while direct `curl` calls are fast, the deadline is being spent before the request starts: a client constructed per request, a cold start, or an event loop busy with other work. Construct the client once, and measure `result.durationMs`.

## Only some calls fall back

A fallback rate of a few percent on a cold edge runtime is normal and costs nothing but a few unrecorded decisions. Log `error.code` and `requestId` and look for a pattern by runtime or region.

## Without the SDK

The same causes apply; the status and `error` code in the response tell them apart. See [Errors](https://docs.trycurious.ai/api-reference/errors.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.