fix(auto): add EAGAIN to INFRA_ERROR_CODES to stop budget-burning retries

EAGAIN (resource temporarily unavailable) is a resource exhaustion error
that cannot be recovered by retrying, yet it was missing from the infra
error set. This caused auto-mode to keep retrying on EAGAIN failures,
burning LLM budget on guaranteed failures.

Fixes #2359

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boucher 2026-03-24 12:57:11 -04:00 committed by Lex Christopherson
parent a53d021864
commit 47405dfda7
2 changed files with 13 additions and 2 deletions

View file

@ -18,6 +18,7 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
"EDQUOT", // disk quota exceeded
"EMFILE", // too many open files (process)
"ENFILE", // too many open files (system)
"EAGAIN", // resource temporarily unavailable (resource exhaustion)
"ECONNREFUSED", // connection refused (offline / local server down)
"ENOTFOUND", // DNS lookup failed (offline / no network)
"ENETUNREACH", // network unreachable (offline / no route)

View file

@ -9,11 +9,11 @@ import { isInfrastructureError, INFRA_ERROR_CODES } from "../auto/infra-errors.j
test("INFRA_ERROR_CODES contains the expected codes", () => {
for (const code of [
"ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE",
"ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
"EAGAIN", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
]) {
assert.ok(INFRA_ERROR_CODES.has(code), `missing ${code}`);
}
assert.equal(INFRA_ERROR_CODES.size, 9, "unexpected extra codes");
assert.equal(INFRA_ERROR_CODES.size, 10, "unexpected extra codes");
});
// ── isInfrastructureError: code property detection ───────────────────────────
@ -48,6 +48,16 @@ test("detects ENFILE via code property", () => {
assert.equal(isInfrastructureError(err), "ENFILE");
});
test("detects EAGAIN via code property", () => {
const err = Object.assign(new Error("resource temporarily unavailable"), { code: "EAGAIN" });
assert.equal(isInfrastructureError(err), "EAGAIN");
});
test("detects EAGAIN in error message fallback", () => {
const err = new Error("spawn failed: EAGAIN resource temporarily unavailable");
assert.equal(isInfrastructureError(err), "EAGAIN");
});
test("detects ECONNREFUSED via code property", () => {
const err = Object.assign(new Error("connect ECONNREFUSED 127.0.0.1:3000"), { code: "ECONNREFUSED" });
assert.equal(isInfrastructureError(err), "ECONNREFUSED");