Skip to content

fix: honor Retry-After minima and request cancellation — SDK-235 - #977

Closed
markstuart-oai wants to merge 15 commits into
mainfrom
markstuart/sdk-235-retry-conformance
Closed

fix: honor Retry-After minima and request cancellation — SDK-235#977
markstuart-oai wants to merge 15 commits into
mainfrom
markstuart/sdk-235-retry-conformance

Conversation

@markstuart-oai

@markstuart-oai markstuart-oai commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Valid server retry minima can be lost through decimal rounding or credential refresh, and cancelling an asynchronous request can leave its transport or retry wait running.

Preserve retry minima with exact decimal parsing and upward timer rounding, retain response headers before closing authentication failures, and return the original error when the delay cannot be represented. Carry cancellation through the concrete stages used by public requests and metadata providers, isolate callers sharing a credential refresh, and remove cancelled waits promptly. The X.509 adapter forwards cancellation to active API I/O, handles cancellation during transport enrollment, and closes responses discarded during those races. Issuer body-read failures retain safe timing metadata while preserving the original I/O cause and sanitized diagnostics.

Validation on the published bytes: 110 focused tests; full native tests (6,794 tests, 22 existing skips); 5,935 Jackson compatibility tests; native build, formatting and lint. Public regressions reproduce the defects before the fixes. Two consecutive independent adversarial review rounds are clean. Trusted-current-main custom-code budget passes at 1,906/2,000.

@markstuart-oai
markstuart-oai requested a review from a team as a code owner September 4, 2026 18:30
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T04:43:07.708812Z 689c242 New commits
🔒 Security Review Completed 2026-09-05T04:35:46.272679Z 689c242 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@openai-sdks

openai-sdks Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 18.701s for Java SDK PR #977.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 335ms
tests/chat-completions-create.test.ts ✅ Passed 578ms
tests/chat-completions-stream.test.ts ✅ Passed 500ms
tests/files-content-binary.test.ts ✅ Passed 247ms
tests/files-create-multipart.test.ts ✅ Passed 337ms
tests/files-list-pagination.test.ts ✅ Passed 386ms
tests/initialize-config.test.ts ✅ Passed 265ms
tests/instance-isolation.test.ts ✅ Passed 274ms
tests/models-list.test.ts ✅ Passed 193ms
tests/responses-background-lifecycle.test.ts ✅ Passed 393ms
tests/responses-body-method-errors.test.ts ✅ Passed 591ms
tests/responses-cancel-timeout.test.ts ✅ Passed 291ms
tests/responses-cancel.test.ts ✅ Passed 334ms
tests/responses-compact-retries.test.ts ✅ Passed 540ms
tests/responses-compact.test.ts ✅ Passed 334ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 736ms
tests/responses-create-advanced.test.ts ✅ Passed 1.836s
tests/responses-create-disconnect.test.ts ✅ Passed 1.164s
tests/responses-create-errors.test.ts ✅ Passed 470ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 357ms
tests/responses-create-retries.test.ts ✅ Passed 347ms
tests/responses-create-stream-failures.test.ts ✅ Passed 283ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 244ms
tests/responses-create-stream-wire.test.ts ✅ Passed 7.094s
tests/responses-create-stream.test.ts ✅ Passed 160ms
tests/responses-create-terminal-states.test.ts ✅ Passed 506ms
tests/responses-create-timeout.test.ts ✅ Passed 321ms
tests/responses-create.test.ts ✅ Passed 1.012s
tests/responses-delete.test.ts ✅ Passed 263ms
tests/responses-input-items-errors.test.ts ✅ Passed 351ms
tests/responses-input-items-list.test.ts ✅ Passed 359ms
tests/responses-input-items-options.test.ts ✅ Passed 317ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 338ms
tests/responses-input-tokens-count.test.ts ✅ Passed 383ms
tests/responses-malformed-inputs.test.ts ✅ Passed 5.902s
tests/responses-not-found-errors.test.ts ✅ Passed 494ms
tests/responses-parse.test.ts ✅ Passed 621ms
tests/responses-retrieve-retries.test.ts ✅ Passed 516ms
tests/responses-retrieve.test.ts ✅ Passed 253ms
tests/responses-stored-method-errors.test.ts ✅ Passed 1.039s
tests/retry-behavior.test.ts ✅ Passed 3.748s
tests/sdk-error-shape.test.ts ✅ Passed 440ms

View OkTest run #33944605526

SDK merge (3d2be733c3be) · head (689c242319d9) · base (198a7bdf339d) · OkTest (2b1bdfd25e98)

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

55 mixed files remain; 0 existing customizations changed.

Compared 198a7bdf339d689c242319d9. Generated baselines verified.

55 existing customizations unchanged
  • openai-java-core/src/main/kotlin/com/openai/models/audio/AudioResponseFormat.kt
  • openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt
  • openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionMessageFunctionToolCall.kt
  • openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionToolMessageParam.kt
  • openai-java-core/src/main/kotlin/com/openai/models/embeddings/Embedding.kt
  • openai-java-core/src/main/kotlin/com/openai/models/embeddings/EmbeddingCreateParams.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionToolCall.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionWebSearch.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseInputItem.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseTextConfig.kt
  • openai-java-core/src/main/kotlin/com/openai/models/videos/Video.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/BetaServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/BetaServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/WebhookServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/WebhookServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/audio/TranscriptionServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/BetaService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/BetaServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/WebhookService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/WebhookServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/audio/TranscriptionServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionServiceImpl.kt
  • openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseFunctionWebSearchTest.kt
  • openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponsesServerEventTest.kt
  • openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFunctionWebSearchTest.kt
  • openai-java-core/src/test/kotlin/com/openai/models/responses/ResponsesServerEventTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/CompletionServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/ImageServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/ResponseServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/WebhookServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/audio/TranscriptionServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/beta/ResponseServiceAsyncTest.kt

15 more in the full report.

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 33944619859 --repo openai/openai-java \
  --name castiron-custom-code-33944619859-1 --dir /tmp/castiron-custom-code-33944619859-1
git apply --stat /tmp/castiron-custom-code-33944619859-1/custom-code.patch
cat /tmp/castiron-custom-code-33944619859-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin 198a7bdf339d3180c11db70a7fd6ee0c96c79376 689c242319d90fea47f895210ad280f615b4f8bf
python3 scripts/castiron/custom_code_report.py report \
  --base 198a7bdf339d3180c11db70a7fd6ee0c96c79376 \
  --head 689c242319d90fea47f895210ad280f615b4f8bf --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-689c242319d9
cat /tmp/castiron-custom-code-689c242319d9/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a651b6ac6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated
Comment thread openai-java-core/src/main/kotlin/com/openai/core/DefaultSleeper.kt Outdated

@jbeckwith-oai jbeckwith-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 9a651b6 and confirmed three blocking cancellation/retry issues already called out inline: (1) CancellableFuture does not override SDK-used stage methods such as thenAccept and exceptionally, so cancellation is disconnected on public void operations and built-in managed-identity provider chains; (2) WorkloadIdentityHttpClient closes a 401 response before capturing headers, so close-sensitive transports can lose Retry-After or replace the intended retryable error; and (3) canceling DefaultSleeper TimerTask instances does not purge them from Timer’s queue, retaining long-delay tasks/futures until their original deadlines. Please address those exact in-scope findings and add concrete path regressions. Current completed CI is green; build/Jackson compatibility remains in progress.

@markstuart-oai

markstuart-oai commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all three findings:

  • Cancellation now propagates through the SDK-used thenAccept and exceptionally stages. The GCP/Azure provider chains wrap their transport futures so public request cancellation reaches pending metadata I/O.
  • Both workload-identity paths capture the 401 error and its headers before closing the response.
  • Retry waits use a daemon scheduled executor with remove-on-cancel enabled, so a cancelled long-delay task releases its future promptly.

Public regressions reproduce each defect before the fix, including void-response requests, actual provider chains, post-close header access and a cancelled long-delay wait. The final focused, full native test/build, formatting and lint checks pass.

Pushed commit 8cd6c16 to this PR branch and verified it on GitHub. No package was published to a registry, and no release or merge was performed. Final validation: 110 focused tests; 6,794 native tests (22 existing skips); 5,935 Jackson compatibility tests; native build, format and lint; trusted-current-main budget 1,906/2,000. Two consecutive independent adversarial review rounds are clean. All three inline findings above are answered and resolved; please re-review the updated implementation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8cd6c16b04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/http/RetryingHttpClient.kt Outdated
@markstuart-oai markstuart-oai changed the title fix: honor Retry-After minima and request cancellation fix: honor Retry-After minima and request cancellation — SDK-235 Sep 4, 2026

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current head addresses the earlier cancellation ownership gaps in a coherent way: CancellableFuture now wraps SDK-used stages such as thenAccept/exceptionally, the X.509 path captures safe retry metadata before response cleanup, and DefaultSleeper uses a ScheduledThreadPoolExecutor with remove-on-cancel rather than retaining cancelled long-delay tasks. Exact decimal retry parsing/upward rounding also avoids shortening server minima. The added public-path cancellation and long-sleep retention regressions are the important part here. I don’t see a remaining blocker in these fixes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: decf8fad88

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated
Comment thread openai-java-core/src/main/kotlin/com/openai/auth/WorkloadIdentityAuth.kt Outdated
Comment thread openai-java-core/src/main/kotlin/com/openai/auth/WorkloadIdentityRetryScope.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ac1417593

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb5d417df7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated
Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed all 23 changed files at cb5d417 against 198a7bd, including the public void/model paths, GCP/Azure metadata chains, shared refresh ownership, X.509 adapter, decimal retry parsing, timer rounding, and all review discussions.

The three earlier requested fixes are present: SDK-used thenAccept/exceptionally stages propagate cancellation, 401 retry headers are captured before close, and canceled waits use scheduler removal. The subsequent retry-metadata and background-generation fixes are also reflected in the code and regression tests. The X.509 cache-owned issuer refresh policy is unchanged from the base.

Two existing findings remain actionable on this head:

  • Source cancellation exceptions: CancellableFuture.cancel invokes the source callback without containment after establishing cancellation, so a throwing custom transport cancel escapes to the public caller.
  • Active handle-stage cleanup: LoggingHttpClient can be inside response status/header access after its parent completes; canceling that completed parent does not close the active response to unblock the handler.

I found no additional distinct issue to add inline. These outstanding cancellation cases prevent approval. Static review only; I did not execute tests or independently validate the reported test results.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

if (terminal.get() && activeResponse.compareAndSet(lease, null)) lease.close()
responseLeaseFuture.complete(lease)

P2 Badge Complete the response lease when cancellation cleanup throws

When cancellation wins just as an X.509 response arrives and that response's close() throws, this callback exits before completing responseLeaseFuture. The response worker remains blocked in get() indefinitely; repeated occurrences can consume every thread in the fixed response executor and make later token exchanges unavailable. Ensure lease publication occurs even if cancellation cleanup fails.

AGENTS.md reference: AGENTS.md:L55-L56

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4283d481aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread openai-java-core/src/main/kotlin/com/openai/core/CancellableFuture.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2eccc96cc3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61c44746c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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.

4 participants