Problem
RoundExecutor replays every provider-request error up to max_attempts based
only on a budget check (local_attempt_index < max_attempts - 1). Deterministic
request failures — 4xx statuses and context_length_exceeded — are re-issued in
full even though retrying them cannot succeed, so a single bad request can be
re-sent the whole configured number of times, amplifying latency and cost before
any error is surfaced.
Root cause
The retry decision does not consult the error category. Both the request_error
(C1) and stream_error (C5) gates classify the category only after the budget is
exhausted, when they already have to build the terminal error. The retry-vs-terminal
semantic already exists in is_retryable_category (Network / RateLimit / Timeout /
ProviderUnavailable are retryable; everything else is terminal), but it is private
to core-types and is not consulted for admission — only for the final classification
after the budget gate has already been passed.
Impact
A deterministic error (for example a 401 auth, 413 payload-too-large, or
context_length_exceeded request) is retried the full number of times even though
every attempt fails the same way. This wastes the attempt budget and the caller's
time on an error that will never recover, and it delays the actual error handling
until the budget is exhausted.
Problem
RoundExecutorreplays every provider-request error up tomax_attemptsbasedonly on a budget check (
local_attempt_index < max_attempts - 1). Deterministicrequest failures — 4xx statuses and
context_length_exceeded— are re-issued infull even though retrying them cannot succeed, so a single bad request can be
re-sent the whole configured number of times, amplifying latency and cost before
any error is surfaced.
Root cause
The retry decision does not consult the error category. Both the
request_error(C1) and
stream_error(C5) gates classify the category only after the budget isexhausted, when they already have to build the terminal error. The retry-vs-terminal
semantic already exists in
is_retryable_category(Network / RateLimit / Timeout /ProviderUnavailable are retryable; everything else is terminal), but it is private
to
core-typesand is not consulted for admission — only for the final classificationafter the budget gate has already been passed.
Impact
A deterministic error (for example a 401 auth, 413 payload-too-large, or
context_length_exceededrequest) is retried the full number of times even thoughevery attempt fails the same way. This wastes the attempt budget and the caller's
time on an error that will never recover, and it delays the actual error handling
until the budget is exhausted.