Skip to main content

Error Handling — TypeScript SDK

All errors thrown by FlareClient are instances of FlareError or one of its subclasses. Import them from @zeridion/flare.

Error hierarchy

FlareError
├── AuthError (401 — invalid or missing API key)
├── QuotaError (402 — quota exceeded)
├── NotFoundError (404 — job not found)
├── ConflictError (409 — idempotency conflict)
└── RateLimitError (429 — rate limit exceeded)

Base class — FlareError

class FlareError extends Error {
readonly code: string; // machine-readable error code from the API
readonly requestId: string; // X-Request-Id value for support
readonly statusCode: number; // HTTP status code
}

Subclasses

AuthError (401)

Thrown when the API key is invalid, expired, or missing.

class AuthError extends FlareError {}

QuotaError (402)

Thrown when your account has exceeded its job quota for the billing period.

class QuotaError extends FlareError {}

NotFoundError (404)

Thrown by cancelJob and retryJob when the job ID does not exist. Note: getJob returns null for 404 instead of throwing.

class NotFoundError extends FlareError {}

ConflictError (409)

Thrown when an idempotency key conflict occurs on createJob — a job with that key already exists and was created with different parameters.

Note: cancelJob and retryJob return null on 409 (state conflict) instead of throwing ConflictError.

class ConflictError extends FlareError {}

RateLimitError (429)

Thrown when the rate limit is exceeded. Includes the reset timestamp so you can implement back-off.

class RateLimitError extends FlareError {
readonly limit: number; // X-RateLimit-Limit — always present on 429 (falls back to 0 if the header is absent)
readonly remaining: number; // X-RateLimit-Remaining — always present on 429 (always 0 in practice)
readonly retryAfter?: number; // Unix epoch seconds when the window resets (X-RateLimit-Reset); undefined if the server omits the header
}

limit and remaining are typed non-optional: the SDK guarantees a numeric value (zero when the server-side header is missing). Only retryAfter is optional, since the server may omit X-RateLimit-Reset for some 429 paths.


Catch patterns

Catch all Flare errors

import { FlareError } from "@zeridion/flare";

try {
await flare.createJob({ job_type: "MyJob", payload: {} });
} catch (err) {
if (err instanceof FlareError) {
console.error(`[${err.statusCode}] ${err.code}: ${err.message} (requestId: ${err.requestId})`);
} else {
throw err; // unexpected — rethrow
}
}

Handle specific errors

import {
FlareError,
AuthError,
RateLimitError,
ConflictError,
QuotaError,
} from "@zeridion/flare";

try {
await flare.createJob({ job_type: "MyJob", payload: {} });
} catch (err) {
if (err instanceof RateLimitError) {
const waitMs = ((err.retryAfter ?? 0) * 1000) - Date.now();
console.warn(`Rate limited. Retry in ${Math.ceil(waitMs / 1000)}s`);
await new Promise(r => setTimeout(r, Math.max(waitMs, 0)));
} else if (err instanceof ConflictError) {
console.log("Idempotency hit — job already enqueued");
} else if (err instanceof QuotaError) {
console.error("Monthly job quota exceeded — upgrade your plan");
} else if (err instanceof AuthError) {
console.error("Invalid API key — check FLARE_API_KEY");
} else if (err instanceof FlareError) {
console.error(err.code, err.requestId, err.statusCode);
} else {
throw err;
}
}

Rate-limit aware retry loop

async function enqueueWithRetry(client: FlareClient, req: CreateJobRequest, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.createJob(req);
} catch (err) {
if (err instanceof RateLimitError && attempt < maxRetries - 1) {
const waitMs = ((err.retryAfter ?? 0) * 1000) - Date.now();
await new Promise(r => setTimeout(r, Math.max(waitMs, 1000)));
} else {
throw err;
}
}
}
}

Non-throwing return values

Two methods return null instead of throwing on state-conflict responses:

MethodReturns null whenThrows on
cancelJob(id)Job is in a non-cancellable state (409)Job not found (404 → NotFoundError)
retryJob(id)Job is not retryable (409)Job not found (404 → NotFoundError)
getJob(id)Job not found (404)API errors

See also