发布

  • [OPIK-6971] Treat insufficient_quota (429) as non-retryable for OpenAI providers (#7148)

    frostbyte_neo 发布于 2026-06-18 09:37:44 +00:00

    • [OPIK-6971] Treat insufficient_quota (429) as non-retryable for OpenAI providers

    When an LLM key returns HTTP 429 insufficient_quota (out of credits), the
    provider keeps failing the same way. LangChain4j maps any 429 to a retryable
    RateLimitException, both in the OpenAiChatModel internal retry and in the outer
    ChatCompletionService retry policy, so an exhausted key was retried repeatedly
    per request (inner x outer attempts), producing an error storm.

    Add a QuotaAwareHttpClient decorator that inspects 429 responses and, when the
    body is insufficient_quota, rethrows a NonRetriableException so both retry layers
    stop immediately. The original body is carried as the exception message (so the
    provider-error mapping still surfaces HTTP 402) and no HttpException is kept as
    the cause (so ExceptionMapper.findRoot cannot re-map the 429 back to retryable).
    rate_limit_exceeded and other statuses pass through unchanged and stay retryable.

    Wired into the free-model and OpenAI completions chat models and the raw OpenAI
    client.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-6971] Use assertThatThrownBy in quota test for consistency

    Address review nit: keep all four QuotaAwareHttpClient tests on the same
    assertion style.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-6971] Address review: dedup builder, case-insensitive match, lombok, test cleanup
    • Extract DelegatingHttpClientBuilder base (timeout forwarding) and have both
      QuotaAwareHttpClient.Builder and InterceptingHttpClientBuilder extend it, instead
      of duplicating the delegation logic.
    • Match insufficient_quota case-insensitively (StringUtils.containsIgnoreCase).
    • Reuse jakarta Response.Status.TOO_MANY_REQUESTS instead of a 429 literal.
    • Use @RequiredArgsConstructor for the boilerplate constructor.
    • Tests: java text blocks, @InjectMocks, parameterized pass-through + casing coverage.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com


    Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com

    下载附件