Repository navigation
fix(sdk): reject negative readiness polling interval in Python and JavaScript - #1826
Merged
Pangjiping merged 2 commits intoSep 14, 2026
Conversation
ReadinessBudget passed the polling interval straight to the sleep call.
With a negative interval the async SDK's asyncio.sleep() returns
immediately, so create/connect/resume/check_ready poll the health
endpoint in a tight loop until the deadline (about 3,500 pings in a
one-second budget against a mock transport, versus 5 with the default
200 ms). The sync SDK's time.sleep() raises ValueError instead, which
surfaces as SandboxInternalException("... sleep length must be
non-negative") after create has already provisioned and killed the
sandbox.
Reject negative intervals with InvalidArgumentException in
ReadinessBudget, and validate before any request in create (when the
health check is not skipped) and resume. A zero interval stays allowed,
since existing tests rely on it.
Dev-next-gen
requested review from
Pangjiping,
hittyt,
jwx0925 and
ninan-nn
as code owners
September 12, 2026 20:06
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f17d41e21
ℹ️ 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".
The JavaScript SDK passed healthCheckPollingInterval straight to setTimeout, which runs a negative delay after about 1 ms. A one-second Sandbox.connect against a health check that keeps returning false made 67 attempts with an interval of -1. Reject negative intervals with InvalidArgumentException before any request in create (when the health check is not skipped), connect, resume and waitUntilReady, matching the Python SDK change. Zero stays allowed, and pool options already reject negative values.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
I noticed that the Kotlin SDK now rejects a non-positive ready polling interval (f494483) because a no-op sleep turns the health check into a spin, and went looking at the Python SDK.
ReadinessBudgethandshealth_check_polling_intervalstraight to the sleep call, with no check.With a negative interval the two Python flavours fail differently:
asyncio.sleep()returns immediately for a negative delay, socreate/connect/resume/check_readypoll/pingin a tight loop until the deadline. Against a mock transport answering 503, a one-secondSandbox.connectsent 5 pings with the default 200 ms interval and about 3,500 withtimedelta(milliseconds=-1).time.sleep()raisesValueError, which comes out asSandboxInternalException: Failed to resume sandbox: sleep length must be non-negative. ForSandboxSync.createthat happens after the sandbox has been provisioned, so it gets killed again because of a client-side argument.This change raises
InvalidArgumentExceptionfor a negative interval inReadinessBudget, and checks it before any request increate(only when the health check is not skipped, since the interval is unused otherwise) and inresume(which calls the resume API before building the budget).connectandcheck_readyare covered by the budget itself, before any request.After review I applied the same check to the JavaScript SDK, which passed
healthCheckPollingIntervalstraight tosetTimeout. Node clamps a negative delay to about 1 ms, so a one-secondSandbox.connectagainst a health check returning false made 67 attempts with-1.create(when the health check is not skipped),connect,resumeandwaitUntilReadynow throwInvalidArgumentExceptionbefore any request. The JS pool options already rejected negative values.I deliberately left a zero interval allowed: the existing tests call
check_ready(..., polling_interval=timedelta(seconds=0)), so I only reject values that never worked in sync mode.Testing
New
tests/test_readiness_polling_interval.py(16 cases, async and sync, create/connect/resume, asserting no HTTP request is sent). All 14 rejection cases fail on main and pass with the change; the full Python SDK suite passes (625 tests), andruff checkandpyrighton the touched files are clean.New
tests/sandbox.polling-interval.test.mjs(create/connect/resume rejections plus a skipped health check case). The three rejection cases fail on main (health check timeout after 67 attempts) and pass with the change. I couldn't runpnpm installon my machine, so I ran the JS tests from the TypeScript sources with Node's type stripping and a stub foropenapi-fetch: the new file plus the create, connect/resume, endpoint-readiness and pool suites give 71 passing tests. ESLint was not run locally.Breaking Changes
A negative interval already crashed the sync SDK; in async it only produced a busy loop. Zero and positive intervals behave as before.
Checklist
AI tools used