Errors & retries
The error types
Section titled “The error types”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 |
Branching on a failure
Section titled “Branching on a failure”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.
What is retried
Section titled “What is retried”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.
Why a retry is free
Section titled “Why a retry is free”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.
Deprecation notices
Section titled “Deprecation notices”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.