Bun 1.4.3 EAI_AGAIN vs ETIMEOUT: retry a Sume submit safely
Bun 1.4.3 reports a temporary DNS failure as EAI_AGAIN, not ETIMEOUT. Update your retry check, and keep one Idempotency-Key across every Sume submit retry.

If your Bun retry loop matches ETIMEOUT to detect a flaky network, Bun 1.4.3 (released October 10, 2026) stops matching it for temporary DNS failures: they now surface as EAI_AGAIN. Add EAI_AGAIN to the retryable set, and send the same Idempotency-Key on every attempt of a Sume submit, so a retry that did reach the API does not start a second billed job.
The Bun release notes list the fix under their retry items: temporary DNS failures reported ETIMEOUT instead of EAI_AGAIN, which broke retry logic (Bun v1.4.3 release notes, read 2026-10-13). The same notes list a retry fix for HTTP/3 when a QUIC connection closed before the response headers arrived. Sume's side of the contract is in Errors and credits.
What changed in Bun 1.4.3
Only the error code changed. A request that fails to resolve api.sume.com before any byte leaves your machine used to look like a timeout, and now looks like a name-resolution retry hint. Code that did if (err.code === "ETIMEOUT") retry() silently stopped retrying DNS blips after the upgrade.
| Item in the notes | What it means for a Sume caller |
|---|---|
| Temporary DNS failure reports EAI_AGAIN instead of ETIMEOUT | Match EAI_AGAIN in your retry check |
| HTTP/3 automatic retry when QUIC closes before response headers | A retry can happen below your code; keep the key stable |
| fetch rejects when Content-Length does not match the body | Send JSON as a string or bytes you measured, not a hand-set length |
Why the key must outlive the retry
A DNS failure means the request never left, so retrying is safe. A timeout or a reset after the body was sent is different: the API may have accepted the job. Sume's docs say to back off on 429, to use retry-after when present, and not to retry unsafe submit requests without an Idempotency-Key. A 503 such as provider_capacity_exceeded says to retry later with the same key.
That makes one rule for the loop: generate the key once per intended job, outside the loop, and reuse it for each attempt. A fresh key per attempt turns every ambiguous failure into a possible duplicate.
A retry loop that fits 1.4.3
This sketch retries name-resolution failures and timeouts a few times with growing waits, and passes the same key every time. It uses the job's own status later, so read Jobs and results for the poll step.
const KEY = crypto.randomUUID(); // once per intended job
const RETRY = new Set(["EAI_AGAIN", "ETIMEOUT", "ECONNRESET"]);
async function submit(body: object) {
for (let attempt = 0; attempt < 4; attempt++) {
try {
const res = await fetch("https://api.sume.com/v1/videos", {
method: "POST",
headers: {
authorization: `Bearer ${process.env.SUME_API_KEY}`,
"content-type": "application/json",
"idempotency-key": KEY,
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
if (res.status === 429 || res.status === 503) {
const wait = Number(res.headers.get("retry-after") ?? 2 ** attempt);
await Bun.sleep(wait * 1000);
continue;
}
return res;
} catch (err: any) {
if (!RETRY.has(err?.code) && err?.name !== "TimeoutError") throw err;
await Bun.sleep(2 ** attempt * 1000);
}
}
throw new Error("submit failed after 4 attempts");
}What to check after upgrading
Grep your retry helpers for the string ETIMEOUT. Where the code classifies errors by code, add EAI_AGAIN. Where it relies on the Sume SDK instead, note that the SDK lets you supply your own fetch, so retries you wrap around it are your responsibility and the same key rule applies.
- Keep the key outside the retry loop and tie it to your own record id.
- Treat
EAI_AGAINas retryable; do not retry4xxvalidation errors. - Honor
retry-afteron429before the next attempt. - After an ambiguous failure, a retry with the same key is the safe move.
Sources
Related posts
More in Developers
- Bun 1.4.3 fetch stream errors: catch a cut-off Sume video download
Bun 1.4.3 fixes response streams that ended cleanly after a transfer failure. Still check the byte count when you save a finished Sume video to disk.
- Extend a Grok Imagine video on Sume: chain by last frame
xAI's guide lists video extension from the final frame. Sume's Grok row has no extend, so pull a late frame with video-frames and start the next clip from it.
- Claude Code 2.1.296: MCP tool names over 128 characters, and Sume's
Claude Code 2.1.296 leaves out an MCP tool whose name exceeds 128 characters. The longest tool name in Sume's hosted list is 28, so none are near it.
- Claude Code subagent autoCompactWindow: keep Sume job ids
Claude Code 2.1.296 lets a subagent auto-compact earlier than the main chat. Keep Sume job ids out of the summary and re-read state with jobs_status.
Written by Sume