Skip to content

Rethrow caller failures instead of reporting them as Bitbucket errors - #11

Merged
mmaikel merged 1 commit into
masterfrom
mikolajstepniewski/propagate-caller-failures
Oct 2, 2026
Merged

mmaikel merged 1 commit into
masterfrom
mikolajstepniewski/propagate-caller-failures

Conversation

@mmaikel

@mmaikel mmaikel commented Oct 2, 2026

Copy link
Copy Markdown

Problem

When Cortex's throttle has used up a tenant's request budget, its OkHttp ThrottleInterceptor refuses the request by throwing IntegrationThrottleException before anything is sent. Cortex relies on that exception reaching the task consumer, which reschedules the task without consuming a retry (Bitbucket Cloud, GitHub and the other integrations do this).

jclouds hands every exception to the API's fallback (InvokeHttpMethod: catch (Throwable t) { return fallback.createOrPropagate(t) }), and our fallbacks turned it into an Error without a status. The signal was lost: in prod, Logic Monitor's scorecard runs kept their previous scores and Paychex's package scans (~10k lookups a day) silently did nothing instead of being rescheduled.

Change

getErrors(Throwable) (used by every *OnError fallback) and RawContentOnError call propagateCallerFailure first: when the HTTP stack failed before any response (HttpResponseException without a response) and the cause is not an IOException, the cause is rethrown.

Failure Before After
Bitbucket answered (any status, readable or not) errors() with the status unchanged
I/O failure without a response (timeout, connection refused) errors(), no status unchanged
Caller's exception before any response (interceptor throttle / rate limit, or a bug) errors(), no status rethrown

Version 3.1.5-CORTEX.

Tests

  • BitbucketFallbacksMockTest: a non-I/O failure before any response is rethrown (the same instance) by getErrors and RawContentOnError — failed before the change; an I/O failure before any response is still an error without a status.
  • ./gradlew check (267 mock tests + checkstyle) passes.
  • brain-backend, against 3.1.5-CORTEX from mavenLocal: a throttle refusal from an interceptor reaches BitbucketOnPremClientServiceImpl's caller as IntegrationThrottleException (fails on 3.1.4-CORTEX); Bitbucket tests pass.

🤖 Generated with Claude Code

A failure the HTTP stack hits before any response that is not an I/O
failure is the caller's own, e.g. an OkHttp interceptor refusing a request
because the caller's throttle budget is used up. The fallbacks turned it
into an Error, so the caller's signal was lost: Cortex's
IntegrationThrottleException, meant to reschedule the task, became a
Bitbucket error. getErrors(Throwable) and RawContentOnError now rethrow
it. Bitbucket's answers (any status) and I/O failures without a response
(timeouts, refused connections) stay errors.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mmaikel
mmaikel marked this pull request as ready for review October 2, 2026 09:50
@mmaikel
mmaikel merged commit 5b4f1e9 into master Oct 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant