SumeInsufficientCreditsError vs SumeRateLimitError: instanceof (TS)
The Sume SDK has typed errors keyed on status and code. Convert a failed result with toSumeApiError, then branch on instanceof. They are on main, not 0.2.0.

A failed call through the generated Sume SDK functions returns a result object with error and response fields. The error is the raw JSON body, typed as unknown, so every integration ends up writing the same unwrap code. The SDK source on the main branch fixes that with typed errors, and they arrive as a small class hierarchy rooted at SumeApiError.
One important caveat: the published @sume-com/sdk 0.2.0 tarball, dated 2026-08-02, does not contain these classes, the retry behaviour or waitForJob. The sample below works only with a build of the SDK from main, so check your installed version before you copy it.
The class map
| Class | Selected by |
|---|---|
| SumeInsufficientCreditsError | Status 402, or code insufficient_credits |
| SumeAuthenticationError | Status 401 |
| SumePermissionError | Status 403 |
| SumeNotFoundError | Status 404 |
| SumeConflictError | Status 409, such as an idempotency conflict |
| SumeRateLimitError | Status 429 |
| SumeServerError | Status 500 and above |
Every class carries code, status, requestId, retryable, retryAfterSeconds, nextAction, details and the raw body. When the response body is not a Sume error envelope at all, such as an HTML 502 from a proxy, you get a plain SumeApiError with code unknown_error rather than a second exception.
Convert, then branch
The helper below runs a read and throws toSumeApiError(...) when there is no data. The loop then branches with instanceof. The client is created with maxRetries: 0 so that the demo sees the 429 itself. Leave the default retries on in production, since they already honour retry-after. The ids poor and slow stand in for requests that return a 402 and a 429.
import {
createSumeClient, getApiJob, toSumeApiError,
SumeInsufficientCreditsError, SumeRateLimitError,
} from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY ?? "", maxRetries: 0 });
async function job(id: string) {
const res = await getApiJob({ client, path: { id } });
if (res.data) return res.data;
throw toSumeApiError(res.response.status, res.error, "getApiJob failed");
}
for (const id of ["poor", "slow"]) {
try {
await job(id);
} catch (e) {
if (e instanceof SumeInsufficientCreditsError) {
console.log("402: add funds, then resubmit with the same key", e.requestId);
} else if (e instanceof SumeRateLimitError) {
console.log("429: wait", e.retryAfterSeconds, "seconds");
} else {
throw e;
}
}
}Notes on using it
- Order your checks from specific to general.
SumeRateLimitErrorandSumeInsufficientCreditsErrorare both subclasses ofSumeApiError, so a first branch onSumeApiErrorwould swallow both. - A 402 is never retryable. Fund the workspace, then resubmit with the same
Idempotency-Key. - Rate limit budgets are per key per minute, and reads and writes have separate budgets.
retryAfterSecondstells you how long to wait. - Log
requestId. It is the same value as thex-sume-request-idresponse header.
The envelope fields are in the error reference, and the client options are in the SDK guide. The published package page is on npm.
Sources
Related posts
More in Developers
- Where the Sume TypeScript SDK runs: Node 18+, Bun, Deno and Workers
@sume-com/sdk has no runtime dependencies and needs only fetch and WebCrypto. Install it, create a client, and know which options and helpers it adds.
- SumeUploadError at step put: the storage upload failed
uploadFile makes three calls. Read SumeUploadError.step to see which failed, and why extra headers on the put step can break the presigned signature.
- Sume video 404 model_not_found: valid model ids for /v1/videos
A video request with an unknown model returns 404 model_not_found, not 400. The ids Sume accepts, how to list them, and the typos that cause it most often.
- Sume video callback_url must be HTTPS: a webhook instead of polling
POST /v1/videos accepts callback_url, which must be HTTPS. Event names, the signature header, retries, and when a poll loop is still the safer choice.
Written by Sume