Skip to main content
Every error thrown by the SDK is a subclass of SpineError, so a single catch (err instanceof SpineError) clause catches anything the SDK can throw.

Error hierarchy

SpineError
├── SpineConnectionError        # network / transport failures
├── SpineTimeoutError           # HTTP timeout or polling timeout
├── SpineRunFailedError         # waitForCompletion: status=failed
└── SpineAPIError               # 4xx / 5xx HTTP responses
    ├── SpineBadRequestError    # 400
    ├── SpineAuthError          # 401
    ├── SpineNotFoundError      # 404
    └── SpineServerError        # 5xx (after retry budget exhausted)

Inspecting errors

SpineAPIError carries the HTTP status, the server’s error message, the request id (useful when reporting issues), and the raw body:
import { Spine, SpineBadRequestError } from 'spine-sdk';

try {
  const client = new Spine({ apiKey: process.env.SPINE_API_KEY! });
  await client.runs.create({ prompt: 'x', template: 'bogus' as 'memo' });
} catch (err) {
  if (err instanceof SpineBadRequestError) {
    console.log(err.statusCode);     // 400
    console.log(err.message);        // "Invalid template: bogus. Valid templates: ..."
    console.log(err.requestId);      // value of X-Request-ID header (if present)
    console.log(err.responseBody);   // parsed JSON body
  }
}
See Errors for the full list of server-side error messages.

Client-side short-circuit

Some validation runs locally without a network round-trip so you get the same typed error regardless of where the check fired:
await client.runs.create({ prompt: 'hi', blocks: [] });     // SpineBadRequestError
await client.runs.retrieve('not-a-uuid');                    // SpineBadRequestError

Automatic retries

The SDK retries transient failures automatically with jittered exponential backoff:
FailureRetried?Notes
Connection errors (DNS, refused, TLS)YesUp to maxRetries.
HTTP 5xxYesUp to maxRetries.
HTTP 400 / 401 / 404NoThrown immediately.
When the retry budget is exhausted, the underlying error (SpineServerError or SpineConnectionError) is thrown.

Tuning retries

const client = new Spine({
  apiKey: process.env.SPINE_API_KEY!,
  maxRetries: 5,    // default: 2, set to 0 to disable retries entirely
});

Timeouts

The HTTP timeout is 60 seconds per request by default. Override it with timeoutMs:
const client = new Spine({
  apiKey: process.env.SPINE_API_KEY!,
  timeoutMs: 120_000,
});
The polling timeout (waitForCompletion) is independent and defaults to 15 minutes. Tune it per call:
await client.runs.waitForCompletion(runId, { timeoutMs: 30 * 60_000 });
SpineTimeoutError is thrown when either timeout fires.

SpineRunFailedError

Thrown by waitForCompletion when the run terminates with status: 'failed'. Carries runId and an errors: { error: string }[] list. If you would rather handle the failed run as a value:
const terminal = await client.runs.waitForCompletion(runId, { resolveOnFailure: true });
if (terminal.status === 'failed') {
  console.error(terminal.errors);
}
A 'partial' status is not a failure — the run produced usable output with some blocks skipped. Inspect terminal.errors on the returned object.