Skip to navigation

Errors

The error envelope, status codes, and retry behaviour.

The envelope

Every error shares one shape:

{
"statusCode": 401,
"timestamp": "2026-08-27T18:57:27.998Z",
"path": "/v1/brains",
"message": "Invalid API key",
"body": {
"message": "Invalid API key",
"error": "Unauthorized",
"statusCode": 401
}
}

body carries the original framework response when available — for validation failures it holds per-field messages, which is usually what you want to surface.

Typed errors

Both SDKs raise a typed error per status, so you can branch without string-matching.

import { LivingBrain, LivingBrainError } from "@livingbrain/sdk";
try {
await client.workspace.getPage({ brainId, slug });
} catch (err) {
if (err instanceof LivingBrain.NotFoundError) {
// no such page in this brain
} else if (err instanceof LivingBrain.TooManyRequestsError) {
// back off and retry
} else if (err instanceof LivingBrainError) {
console.error(err.statusCode, err.message, err.body);
}
}

Status codes

CodeMeaningWhat to do
400Malformed requestRead body for per-field detail. Don’t retry unchanged.
401Missing API key / Invalid API keyCheck the x-api-key header. See Authentication.
404Not found — or not yoursConfirm the x-subject-id owns this brain.
429Rate limitedBack off and retry; the SDKs do this for you.
5xxServer errorRetried automatically.

A 404 is also what you get for a brain that exists but belongs to a different subject — the API doesn’t distinguish, so it can’t be used to probe for other users’ brains.

Retries

Both SDKs retry 429 and 5xx automatically with exponential backoff. Tune per call:

await client.brains.list({ maxRetries: 5, timeoutInSeconds: 30 });

400, 401, and 404 are not retried — they won’t succeed on a second attempt.