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.

4 min readSume
All posts

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

Sume SDK error classes on main and what selects them, from the SDK source (read 2026-10-03)
ClassSelected by
SumeInsufficientCreditsErrorStatus 402, or code insufficient_credits
SumeAuthenticationErrorStatus 401
SumePermissionErrorStatus 403
SumeNotFoundErrorStatus 404
SumeConflictErrorStatus 409, such as an idempotency conflict
SumeRateLimitErrorStatus 429
SumeServerErrorStatus 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. SumeRateLimitError and SumeInsufficientCreditsError are both subclasses of SumeApiError, so a first branch on SumeApiError would 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. retryAfterSeconds tells you how long to wait.
  • Log requestId. It is the same value as the x-sume-request-id response 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

All Developers posts

Written by Sume