Errors
What the SDK throws, and how to tell the kinds apart.
Every failure is a SubakoError: status, code, body, and a message. The seven codes the API declares have a class each, and a code this version has not heard of still arrives with its code and message intact.
import { ConflictError, NotFoundError, SubakoError } from "@subako-ai/sdk";
try {
await subako.sessions.postEvent(sessionId, { type: "input", text });
} catch (error) {
if (error instanceof NotFoundError) {
// ...
} else if (error instanceof ConflictError) {
// ...
} else if (error instanceof SubakoError) {
console.error(error.status, error.code, error.message);
}
}
The classes
| Class | When |
|---|---|
UnauthorizedError |
The credential was missing, malformed, or refused — and a refresh did not settle it. |
ForbiddenError |
The credential is valid and lacks the permission, or names another workspace. |
NotFoundError |
No such thing, or the caller cannot see it. |
InvalidRequestError |
The request itself needs changing. |
ConflictError |
The state will not take it — a duplicate idempotency key, a sandbox still settling. |
ClientOutdatedError |
This SDK is behind what the server now requires. |
InternalError |
The server failed. |
Two more are the SDK’s own rather than the API’s:
SubakoConnectionError— no response arrived at all.SubakoTimeoutError— the attempt outlived itstimeout.
All of them extend SubakoError, so one instanceof catches the lot.
Aborts are not errors
An AbortSignal you abort yourself is rethrown untouched, never wrapped. What comes out is the abort reason — whatever you passed to abort(reason), or the AbortError DOMException the platform supplies when you passed nothing.
const controller = new AbortController();
const reason = new Error("the person navigated away");
try {
await subako.agents.get(agentId, { signal: controller.signal });
} catch (error) {
if (error === reason) {
// our own cancellation, not a failure
}
}
controller.abort(reason);
So a caller that cancels deliberately can tell its own cancellation from a failure without inspecting a message.
A code this version has not heard of
The class list is closed; the code list is not. A code the server added after this SDK shipped arrives as a plain SubakoError with error.code set to whatever the server sent, so a switch on error.code keeps working and only the instanceof narrowing misses out.
if (error instanceof SubakoError) {
switch (error.code) {
case "precondition_failed":
case "too_many_requests":
// codes the API grew later; no class, and no reason to wait for one
break;
}
}