Resolve the MCP session name from a single source in the alarm path - #1801
Merged
Conversation
The alarm guard read the durable name record while every later read went through PartyServer, which consults only ctx.id.name and an in-memory field the alarm path never populates. An alarm could pass the guard and then throw on a session id read for a log line. Route all reads through one accessor and make observational reads total.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | cadf6ba | Aug 28 2026, 04:29 AM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | cadf6ba | Commit Preview URL Branch Preview URL |
Aug 28 2026, 04:26 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
RhysSullivan
marked this pull request as ready for review
August 28, 2026 04:40
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.
Problem
The MCP session Durable Object's alarm could die reading the session id it had
just decided existed.
PartyServer resolves a DO's name from three places, and does not consult them in
one place: the
namegetter readsctx.id.nameand an in-memory field that ishydrated only during initialization, while the durable
__ps_namerecord isread only by that initialization. The alarm handler makes most of its
decisions itself and delegates to
super.alarm()on one branch only, so itnever runs that hydration.
The alarm's unaddressable-session guard read the durable record directly. On an
invocation without a
ctx.id.nameit therefore concluded the session wasaddressable, continued — and threw on the very next read of the session id,
which was there to put an id in a log line about the decision it had just
made. The lease branches log before they act, so the extension was lost with the
line: the alarm died, retried, and the session stayed pinned without making
progress.
Fix
One accessor now answers "what is this DO's name", consulting
ctx.id.name, thein-memory field, and the durable record, with a defined fallback order. The
alarm resolves the name through it up front and remembers the answer, so the
guard and every read after it agree by construction.
Separately, and independently of that ordering: a read of the session id for a
log line or a span attribute can no longer abort the work it is describing.
Observational reads go through a total accessor that falls back to a placeholder
instead of throwing. Callers that genuinely cannot proceed without an id —
execution-owner routing, approval URLs — still get the strict accessor and its
throw, because a wrong id is worse there than a failure.
An alarm that can resolve no name from any source now logs that and exits
cleanly after releasing the runtime and dropping the alarm, rather than throwing
into an endless retry.
Testing
packages/hosts/cloudflare/src/mcp/agent-session-durable-object.test.ts: fournew cases over the existing ctx/storage harness — an alarm on a DO whose
ctx.id.nameis unset but whose durable record exists disposes the sessionthe record names; the same shape extends a paused lease instead of dying on
its log; an alarm with no name from any source completes and cleans up; an
observational id read never throws. Full file: 23 passed.
getter fails all four new cases and leaves the pre-existing 19 passing.
packages/hosts/cloudflareMCP unit suites: 89 passed.cloud/mcp-session-cold-init.test.tsandcloud/mcp-destroyed-session-envelope.test.ts: both pass, before and after.typecheckandlintgreen.This is verified at the unit level by the declared exception for cases the dev
stack cannot produce: miniflare addresses every Durable Object by name, so an
alarm with an unset
ctx.id.namecannot be provoked black-box.