Skip to content

fix(local): round-trip RPC success values through marker serialization#856

Open
asterikx wants to merge 1 commit into
alchemy-run:mainfrom
asterikx:fix/rpc-serialize-success-values
Open

fix(local): round-trip RPC success values through marker serialization#856
asterikx wants to merge 1 commit into
alchemy-run:mainfrom
asterikx:fix/rpc-serialize-success-values

Conversation

@asterikx

Copy link
Copy Markdown

Bug

alchemy dev (since the capnweb RPC split) crashes on any provider whose result contains an Effect Redacted:

TypeError: Cannot serialize value: <redacted>
    at evaluateImpl (capnweb/dist/index.js:1636:48)
    at provider.update (alchemy/src/Apply.ts:123:14)

Repro: any Cloudflare Container with a Redacted env value (e.g. Config.redacted(...) or an Output-mapped Redacted.make) under alchemy dev @ 2.0.0-beta.63 — create/update of the container fails, alchemy dev: apply failed. The container provider's result embeds dev.env: Record<string, string | Redacted> (LocalContainerProvider), which capnweb (correctly) refuses to serialize.

Cause

Local/RpcSerialization.ts marker-encodes RPC arguments (serializeRpcArgs/deserializeRpcArgs turn Redacted/Output into {_tag} markers) — but wrapRpcEffectHandler returns { _tag: "Success", value: exit.value } with the value raw, and unwrapRpcEffectHandler does Exit.succeed(exit.value) without decoding.

Fix

Success values now round-trip the same marker (de)serialization as arguments, on both sides. Two return-value tests added — they fail on current main and pass with the fix (14/14 in test/Local/RpcSerialization.test.ts).

Note

wrapRpcStreamHandler/unwrapRpcStreamHandler pipe stream elements raw as well — if streamed values can ever carry Redacted/Output, the same treatment is needed there. Left out of this PR since I couldn't confirm a live path that streams such values; happy to extend if you want it symmetric.

We hit this in production dev-loop usage (zero-cache + Python containers with secret env under alchemy dev) and are running exactly this change as a local patch meanwhile.

🤖 Generated with Claude Code

RPC arguments are marker-encoded (Redacted/Output -> {_tag} markers) before
crossing the capnweb session, but effect-handler success values crossed raw.
Any provider result containing a Redacted — e.g. a Cloudflare Container's
dev.env — crashed alchemy dev at apply with
"TypeError: Cannot serialize value: <redacted>".

Wrap now serializes exit values symmetrically to args; unwrap reifies the
markers back. Adds red/green covered return-value round-trip tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sam-goodwin

Copy link
Copy Markdown
Contributor

Is there a test we can add?

@asterikx

Copy link
Copy Markdown
Author

There are two in the PR already — packages/alchemy/test/Local/RpcSerialization.test.ts gains a return value serialization block:

  • round-trips a Redacted return value — a handler returning Redacted.make("hush"); the existing roundTrip harness threads the JSON wire hop, so on main the value comes back corrupted instead of a reconstructed Redacted
  • round-trips Redacted values nested in a returned object — the container-provider shape ({ env: { TOKEN: Redacted } }) that crashes alchemy dev in practice

Red/green verified: on main (fix stashed) exactly these two fail — Tests: 2 failed | 12 passed; with the fix 14 passed.

Happy to also cover the stream-element path (wrapRpcStreamHandler has the same gap), but that needs the symmetric stream fix first — say the word and I will extend the PR to both.

🤖 Generated with Claude Code

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.

3 participants