Skip to content

fix(runtime): fail released context handles instead of truncating them - #2076

Merged
eersnington merged 2 commits into
mainfrom
fix/context-released-handles
Oct 21, 2026
Merged

eersnington merged 2 commits into
mainfrom
fix/context-released-handles

Conversation

@eersnington

Copy link
Copy Markdown
Member

Stacked on #2067. Follow-up to #2073.

#2073 releases the timers and handles a context call leaves behind. Released sockets ended cleanly, so work that crossed a call boundary lost data or hung without an error.

Case Before After
Call 1 stores a fetch Response; call 2 reads the body succeeded with a truncated body (0 bytes of 10 MB) rejects with ERR_AGENTOS_CONTEXT_HANDLE_RELEASED
fetch still in flight at the end of call 1, awaited in call 2 never settles; call 2 times out and the context is wiped rejects with cause.code ERR_AGENTOS_CONTEXT_HANDLE_RELEASED
Call that fully reads its own fetch stderr: cancelled setTimeout x1 no stderr
  • A released socket is destroyed with a typed error that names the call boundary, so its readers and pending requests fail instead of ending early.
  • Only ref'd timers and immediates are released, the same rule as handles. Unref'd runtime timers, such as undici's, keep working across calls.
  • Errors raised while releasing handles go to that call's stderr and never change its outcome.
  • javascript.mdx documents what happens to timers, handles, in-flight requests, and stored response bodies at the end of a call.

The undici stream shim's finished() polled web streams with a ref'd 0 ms timer until they closed. An unread fetch body never closes, so the timer kept the guest process alive and busy. Watch the web-streams-polyfill state transition instead, so finished() holds no event-loop reference, matching Node's eos.
When a context call or evaluation completes, sockets it left open are now destroyed with ERR_AGENTOS_CONTEXT_HANDLE_RELEASED, so a stored fetch Response body or an in-flight fetch fails with that error in a later call instead of ending early or hanging. Only ref'd timers are cancelled; unref'd runtime timers (undici's shared timer, stream completion polling, which is now unref'd) keep working across calls and no longer show up as leftover work.

The call's result is finalized before the release. Failures and unhandled rejections raised by the release are written to the call's stderr and no longer fail the completed call or leak into a later one.
@github-actions

Copy link
Copy Markdown
Contributor

📟 Pip-Boy · 2a9ef33

📦 Packages · fresh npm install resolve, no lockfile · this PR vs base

No notable install size, dependency, or entrypoint changes across 6 packages.

All 6 packages · linux-x64-gnu
package (linux-x64-gnu) @latest base this PR Δ vs base packages
@rivet-dev/agentos-core 458.2 MB 325.9 MB 325.9 MB 0 10 (0)
@rivet-dev/agentos-node-pty 7.6 KB 18.0 KB 18.0 KB 0 1 (0)
@rivet-dev/agentos-posix 253.6 MB 253.6 MB 253.6 MB 0 7 (0)
@rivet-dev/agentos-runtime-core 253.6 MB 253.6 MB 253.6 MB 0 6 (0)
@rivet-dev/agentos-sandbox 495.5 MB 363.5 MB 363.5 MB 0 85 (0)
@rivet-dev/agentos-toolchain 130.8 KB 141.2 KB 141.2 KB 0 2 (0)

🧹 Rust dependencies · cargo deny + cargo shear

check new in this PR fixed existing on base
advisories ✅ 0 0 25
licenses ✅ 0 0 0
sources ✅ 0 0 0
bans ✅ 0 0 0
unused ✅ 0 0 16

🦀 Binaries · publish Dockerfiles, --release

Base: main@9413c84, the newest main commit with native builds before the merge base. Size changes merged to main since then show up here too.

artifact npm @latest base this PR Δ vs base
agentos-native-sidecar linux-x64-gnu 143.6 MB 143.7 MB 143.7 MB +4.2 KB (+0.0%)

⏱ Timing

job wall time slowest step
changes 33s checkout · 28s
zizmor 11s checkout · 3s
hygiene 57s checkout · 24s
footprint 2m31s Pack this commit · 48s
native · linux-x64-gnu 9m55s Build with the publish Dockerfile · 9m31s
⏭ self-test — skipped
report 25s setup-node · 9s
🔭 Full CI trace for this commit

One OpenTelemetry trace of CI and Pip-Boy for 2a9ef33: every job and step, with the sizes above attached. Run after CI finishes.

pnpm install --frozen-lockfile --filter 'pipboy...'
pnpm --filter pipboy pipboy trace --sha 2a9ef330c64a40afa2ca84d2e0447cd442839a75

Add --otlp <url> to send it to any OTLP/HTTP collector.

Agent instruction: From a rivet-dev/agentos checkout, run the commands above, then read the trace file the last command prints. List the slowest jobs and steps and explain where CI time went.

Base automatically changed from fix/fetch-unread-body-liveness to main October 21, 2026 19:22
@eersnington
eersnington merged commit 02c0aaf into main Oct 21, 2026
16 checks passed
@eersnington
eersnington deleted the fix/context-released-handles branch October 21, 2026 19:22
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