fix(ai/embed): recognize OpenAI 'maximum request size' error in isTokenLimitError

OpenAI's /v1/embeddings endpoint hard-caps a single request at 300k tokens
total across all input items. When the cap is exceeded it returns:

    Invalid 'input': maximum request size is 300000 tokens per request.

None of the three existing regexes in isTokenLimitError matched this
phrasing, so the recursive-halving safety net in embedSubBatch never
engaged for OpenAI. The same fat page (a token-dense markdown export,
e.g. a Discord transcript) would re-fail every pass, blocking forward
progress on the whole batch indefinitely.

Locally reproduced on a 31,129-chunk Postgres brain: 2,125 chunks
stuck at 'remaining' across 30+ embed --stale passes with retry
loops + sleep delays. Adding the two new patterns lets halving fire;
the same backlog cleared in one pass after the regex change (the
companion max_batch_tokens recipe fix from PR #924 caps fresh batches,
but existing oversize pages still need halving to recover).

Adds:
  - /maximum request size.*tokens/i  — OpenAI verbatim
  - /max.*tokens.*per.*request/i    — defensive against minor rewording

Tests:
  - Regression test for the exact OpenAI error string
  - Coverage for the generic 'max tokens per request' variant
  - All 25 tests in adaptive-embed-batch.test.ts pass

No behavior change for providers whose errors already matched.

(cherry picked from commit b834e84c56)
This commit is contained in:
Matt Gunnin
2026-05-24 01:08:16 -07:00
committed by Garry Tan
parent 651628956a
commit e17ea13745
2 changed files with 19 additions and 1 deletions
+4 -1
View File
@@ -1259,7 +1259,10 @@ export function isTokenLimitError(err: unknown): boolean {
return (
/max.*allowed.*tokens.*batch/i.test(msg) ||
/batch.*too.*many.*tokens/i.test(msg) ||
/token.*limit.*exceeded/i.test(msg)
/token.*limit.*exceeded/i.test(msg) ||
// OpenAI embeddings: "Invalid 'input': maximum request size is 300000 tokens per request."
/maximum request size.*tokens/i.test(msg) ||
/max.*tokens.*per.*request/i.test(msg)
);
}
+15
View File
@@ -155,6 +155,21 @@ describe('isTokenLimitError (pure helper)', () => {
expect(isTokenLimitError(new Error('Batch contains too many tokens'))).toBe(true);
});
test('matches OpenAI embeddings "maximum request size" error (regression: PR ###)', () => {
// Real error string returned by OpenAI's /v1/embeddings endpoint when the
// sum of all input items exceeds 300k tokens. Without this match, gbrain's
// recursive-halving safety net never engages on OpenAI and the queue stalls
// forever on token-dense pages.
const openaiErr = new Error(
"Invalid 'input': maximum request size is 300000 tokens per request.",
);
expect(isTokenLimitError(openaiErr)).toBe(true);
});
test('matches generic "max tokens per request" phrasing', () => {
expect(isTokenLimitError(new Error('Exceeded 300000 max tokens per request'))).toBe(true);
});
test('does not match unrelated errors', () => {
expect(isTokenLimitError(new Error('Connection refused'))).toBe(false);
expect(isTokenLimitError(new Error('Invalid API key'))).toBe(false);