Skip to content

fix(services/s3): keep retryable sign errors temporary - #8458

Open
DimaRabkin wants to merge 1 commit into
apache:mainfrom
DimaRabkin:fix/s3-retryable-sign-error
Open

DimaRabkin wants to merge 1 commit into
apache:mainfrom
DimaRabkin:fix/s3-retryable-sign-error

Conversation

@DimaRabkin

Copy link
Copy Markdown

Which issue does this PR close?

Closes #8457.

Rationale for this change

For general-purpose buckets, S3 reports every signing failure as a persistent Unexpected error, even when reqsign marks the failure retryable. A transient credential failure, such as a failed STS AssumeRole send, is therefore never retried by RetryLayer. The S3 Express path already keeps the flag.

Today: a retryable reqsign error becomes a persistent "signing http request" error.

After this PR: a retryable reqsign error becomes a temporary error, so RetryLayer retries it. A persistent reqsign error stays persistent. The error kind and message are unchanged.

This PR fixes the OpenDAL half. Today ProvideCredentialChain in reqsign drops retryable provider errors before they reach OpenDAL; apache/reqsign#926 fixes that. S3 always wraps its providers in a chain, so the retry also needs that fix. It ships as a semver-compatible reqsign-core 3.3.x release, so no dependency change is needed here.

What changes are included in this PR?

  • S3Core::sign_error passes is_retryable() through as with_temporary for general-purpose buckets, as it already does for S3 Express.
  • S3Builder::build delegates to an inherent build_backend that returns the concrete S3Backend, so tests can replace the signer.
  • Tests:
    • test_s3_retryable_credential_error_is_temporary: a credential provider fails once with a retryable error and then succeeds. The first stat fails with a temporary error before any request is sent; the retry signs with the loaded credential. It fails on main (is_temporary() is false).
    • test_s3_persistent_credential_error_is_not_temporary: a persistent credential error stays persistent.

The tests install the provider directly on the signer, not inside a ProvideCredentialChain, because the chain drops the retryable error until the reqsign fix is released.

Are there any user-facing changes?

Retryable signing failures on general-purpose S3 buckets are now temporary errors, so RetryLayer retries them.

Breaking changes

AI Usage Statement

  • Harness: Claude Code (desktop app)
  • Model: Claude Opus 5.5 (claude-opus-5-5)
  • Effort: default
  • Role: traced the error path from reqsign to RetryLayer, wrote the change and tests, and drafted this description. The failure was observed in production against AWS STS (one transient AssumeRole send failure); the tests simulate the provider failure.

What: For general-purpose buckets, S3 maps a retryable reqsign error to a
temporary OpenDAL error, as the S3 Express path already does.

Why: Every signing failure became a persistent Unexpected error, so
RetryLayer never retried a transient credential failure such as a failed
STS AssumeRole send.

How: S3Core::sign_error passes is_retryable() through with_temporary.
S3Builder::build delegates to build_backend so tests can replace the
signer. Tests cover a provider that fails once with a retryable error and
then succeeds, and a persistent error that stays persistent.
@DimaRabkin
DimaRabkin requested a review from Xuanwo as a code owner November 1, 2026 09:19
@github-actions github-actions Bot added releases-note/fix The PR fixes a bug or has a title that begins with "fix" services/s3 size:L This PR changes 100-499 lines, ignoring generated files. labels Nov 1, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

releases-note/fix The PR fixes a bug or has a title that begins with "fix" services/s3 size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: S3 reports retryable credential errors as persistent sign errors

1 participant