Sume SDK: try/catch misses a 402, generated calls return { error }
Generated @sume-com/sdk operations return { data, error, response } instead of throwing, so a 402 or 429 slips past try/catch. Check error on every call.

With @sume-com/sdk, a generated operation such as generateVideoV1 or listFormats returns an object with data, error and response; it does not throw on an HTTP error status, so a try/catch around it will not catch a 402 insufficient_credits or a 429 rate_limited. Check error after every call. The package README shows the pattern: destructure { data: submitted, error }, then if (error) throw ... (TypeScript SDK).
The helpers behave differently on purpose. waitForJob throws SumeJobRequestError when a status read fails and SumeJobTimeoutError when the deadline passes, but it resolves, not throws, for a failed or canceled job, since that is a result you asked for.
What does a safe call look like?
Check error first, read response.status for the HTTP code, and take the code and request id from the error envelope.
import { createSumeClient, generateVideoV1, waitForJob } from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
async function main() {
const { data, error, response } = await generateVideoV1({
client,
headers: { "idempotency-key": "mug-clip-v1" },
body: { prompt: "Slow push-in on a ceramic mug", mode: "async" },
});
if (error || !data) {
const e = (error as { error?: { code?: string; request_id?: string } })?.error;
throw new Error(`submit ${response?.status} ${e?.code} ${e?.request_id}`);
}
const job = await waitForJob(data.data.request_id, { client });
console.log(job.status);
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});Which outcomes throw and which return?
| Call | HTTP error status | Terminal failed job | Deadline passed |
|---|---|---|---|
| Generated op (generateVideoV1, listFormats) | Returns { error } | Not applicable | Client timeout surfaces as a fetch failure |
| waitForJob | Throws SumeJobRequestError | Resolves with the job record | Throws SumeJobTimeoutError |
| waitForRun | Throws SumeRunRequestError | Resolves with the receipt | Throws SumeRunTimeoutError |
| subscribeFormatRun | Throws when create is refused | Resolves with the receipt | Throws a run timeout error |
What does the client retry for you?
The client created with createSumeClient retries 408, 429 and 5xx responses and transport failures, twice by default, with exponential backoff and jitter, and honors retry-after. It only replays a POST when you supplied an Idempotency-Key, since replaying a create without one could start and bill a second job. That is one more reason to always pass the header on creates.
What should you do about it?
- Wrap generated calls in one helper that throws on
error, so a missed check cannot become a silent undefined. - Branch on the error
codeandretryable, not on the message text. - Log the
request_idfrom the envelope on every failure.
Sources
Related posts
More in Developers
- Sume SDK error.retryable: server flag first, status only as fallback
SumeApiError.retryable uses the error envelope's retryable flag when present and falls back to 408, 429 or 5xx otherwise. A 409 is never retried by status.
- Sume STT language_code: set a hint or omit it for auto-detect?
language_code is optional on Sume STT. Omit it to auto-detect, pass a BCP-47 hint like en or ko when you know the language. A quick way to choose.
- Sume STT takes 10 minutes per request: a 90-minute file is 9 jobs
Sume speech-to-text caps a request at 600 seconds of audio, so a 90-minute recording is nine requests at up to $0.10 each, $0.90 in total.
- Turn Sume STT word timings into an SRT file in 30 lines of Python
Sume speech-to-text returns words[] with start and end seconds. Group them into SRT cues of 42 characters or 5 seconds, and see what the caption endpoint takes.
Written by Sume