Skip to content

Errors & retries

Everything the SDK throws extends LayerError, so one catch covers it.

Class When
LayerApiError The API answered with a problem document
LayerRunFailedError A generation or training run reached a terminal state that is not success
LayerBudgetExceededError A run was priced above maxCreativeUnits, so nothing was submitted
LayerTimeoutError A request, or a wait for a run, outlived its deadline
LayerConnectionError The request never got an answer

Branch on code — the machine-readable identifier — never on the message, which is prose and may be reworded:

import { LayerApiError, LayerRunFailedError } from '@layer_ai/sdk'
try {
await layer.inferences.generate({ prompt: '' })
} catch (error) {
if (error instanceof LayerRunFailedError && error.isInsufficientBalance) {
// The workspace ran out of Creative Units. Top up and resubmit.
}
if (error instanceof LayerApiError && error.code === 'CONTENT_POLICY_VIOLATION') {
// The prompt was refused. Rewriting it is the fix; retrying it is not.
}
throw error
}

A LayerApiError carries the whole problem document — status, code, title, detail — plus retryAfterSeconds and the quota state in rateLimit when the API reported them. See errors for the codes themselves.

A request the server said was worth sending again — a 429, a 503, a dropped connection — is retried with exponential backoff, honouring Retry-After when the server sends one. Three retries by default:

const layer = new Layer({ apiKey, retry: { maxRetries: 5, initialDelayMs: 250, maxDelayMs: 10_000 } })

maxRetries: 0 sends each request exactly once.

A 422 is never retried: no amount of resending fixes a request the API refused on its contents.

Every unsafe request carries an Idempotency-Key, minted by the SDK when you supply none. A generation that was accepted but whose response was lost is therefore replayed on the retry rather than run — and paid for — a second time.

Supply your own key when a logical operation spans more than one call into the SDK, so your own retry replays too:

await layer.inferences.generate({ prompt: '' }, { idempotencyKey: `nightly-batch-${date}-${index}` })

Keys are replayable for 24 hours and scoped to your credential’s owner. Reusing one with a different request is a client bug, and the API says so with IDEMPOTENCY_KEY_REUSED rather than returning the wrong result.

The API announces an endpoint it intends to withdraw long before it stops working. Hear about it from your own traffic:

const layer = new Layer({
apiKey,
onDeprecation: (notice) => console.error(`${notice.path} is deprecated, sunset ${notice.sunset}`),
})

Each endpoint is announced once per client. See the deprecation policy for the timeline a notice commits to.