Skip to content

fix(rpc): make RpcSerialization.msgPack options configurable#6161

Open
bohdanbirdie wants to merge 1 commit intoEffect-TS:mainfrom
bohdanbirdie:fix/rpc-msgpack-cf-workers
Open

fix(rpc): make RpcSerialization.msgPack options configurable#6161
bohdanbirdie wants to merge 1 commit intoEffect-TS:mainfrom
bohdanbirdie:fix/rpc-msgpack-cf-workers

Conversation

@bohdanbirdie
Copy link
Copy Markdown

@bohdanbirdie bohdanbirdie commented Apr 8, 2026

Summary

  • Adds makeMsgPack(options) factory for creating MessagePack serialization with custom msgpackr options
  • Existing msgPack and layerMsgPack exports are unchanged (no breaking change)
  • Fixes silent error swallowing in msgPack decode — non-incomplete errors are now rethrown instead of returning []

Problem

On Cloudflare Workers with allow_eval_during_startup (default for compatibility_date >= 2025-06-01), RpcSerialization.msgPack silently fails when decoding messages containing 3+ objects with the same key structure.

Root cause: new Packr() with no options sets this.structures = [] because undefined != false evaluates to true. This enables msgpackr's record/structure path. When the Unpackr's readObject.count exceeds the JIT threshold (2), msgpackr calls new Function() to compile a fast reader — which CF Workers blocks during request handling with EvalError: Code generation from strings disallowed for this context.

The existing catch { return [] } in RpcSerialization.msgPack silently swallows this error, returning an empty response. The caller never receives data.

Reproduction

https://github.com/bohdanbirdie/repro-effect-rpc-msgpack-cf-workers

  • main branch — "before" state: reproduces the bug using inline msgpackr code (same as RpcSerialization.msgPack)
  • fixed branch — "after" state: uses bun patch on @effect/rpc to apply this PR's changes, worker uses RpcSerialization.makeMsgPack({ useRecords: false })

Deploy either branch to CF Workers with npx wrangler deploy and curl the endpoint.

Fix

Use makeMsgPack to create a serialization with custom options:

import { Layer } from "effect"
import { RpcSerialization } from "@effect/rpc"

Layer.succeed(
  RpcSerialization,
  RpcSerialization.makeMsgPack({ useRecords: false })
)

This skips this.structures = [] in the Packr constructor, preventing the record/JIT path entirely.

Test plan

  • New unit tests for msgPack and makeMsgPack with custom options
  • Existing 101 e2e RpcServer tests pass (http, ws, tcp, worker × ndjson, msgpack, jsonrpc)
  • CF Workers deployment verified with { useRecords: false }

References

@github-project-automation github-project-automation bot moved this to Discussion Ongoing in PR Backlog Apr 8, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

⚠️ No Changeset found

Latest commit: 5a7e0d4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

bohdanbirdie added a commit to bohdanbirdie/repro-effect-rpc-msgpack-cf-workers that referenced this pull request Apr 8, 2026
Uses bun patch to apply the fix from Effect-TS/effect#6161:
- msgPack() and layerMsgPack() accept optional msgpackr.Options
- Non-incomplete decode errors are rethrown instead of silently returning []

Worker uses RpcSerialization.msgPack({ useRecords: false }) to avoid
msgpackr JIT new Function() on CF Workers.

Compare with `main` branch for the "before" state.
Adds `makeMsgPack(options)` factory that accepts `msgpackr.Options`,
allowing Cloudflare Workers users to pass `{ useRecords: false }` to
prevent msgpackr's JIT code generation via `new Function()`, which is
blocked during request handling.

Existing `msgPack` and `layerMsgPack` exports are unchanged (no
breaking change).

Also fixes silent error swallowing in the msgPack decode path —
non-incomplete errors are now rethrown instead of returning `[]`.
@bohdanbirdie bohdanbirdie force-pushed the fix/rpc-msgpack-cf-workers branch from 078fc50 to 5a7e0d4 Compare April 8, 2026 20:19
@bohdanbirdie bohdanbirdie marked this pull request as ready for review April 8, 2026 20:21
@bohdanbirdie bohdanbirdie requested a review from tim-smart as a code owner April 8, 2026 20:21
@bohdanbirdie
Copy link
Copy Markdown
Author

I'm not sure if the solution is good enough, but I think that the underlying issue is confirmed. I'm rather new to effect so PR changes might need some guidance, but I'm happy to carry on with it.

Reproduction repository should be easy to use and try.

Tim, let me know what you think (didn't want to ping and create noise).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

1 participant