Skip to content

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

Merged
tim-smart merged 3 commits into
Effect-TS:mainfrom
bohdanbirdie:fix/rpc-msgpack-cf-workers
Apr 22, 2026
Merged

fix(rpc): make RpcSerialization.msgPack options configurable#6161
tim-smart merged 3 commits into
Effect-TS:mainfrom
bohdanbirdie:fix/rpc-msgpack-cf-workers

Conversation

@bohdanbirdie
Copy link
Copy Markdown
Contributor

@bohdanbirdie bohdanbirdie commented Apr 8, 2026

Fixes #6170

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

🦋 Changeset detected

Latest commit: 964bb3d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@effect/rpc Patch
@effect/cluster Patch
@effect/platform-bun Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/workflow Patch
@effect/ai Patch
@effect/sql-clickhouse Patch
@effect/ai-amazon-bedrock Patch
@effect/ai-anthropic Patch
@effect/ai-google Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another 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.
@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
Contributor 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).

bohdanbirdie added a commit to bohdanbirdie/livestore that referenced this pull request Apr 13, 2026
CF Workers blocks `new Function()` during request handling (CSP).
msgpackr's default build uses JIT code generation via `new Function()`
when decoding 4+ same-structure objects in a single unpackMultiple call.
This causes @effect/rpc's msgPack serialization to silently return empty
responses on deployed CF Workers.

Switch to msgpackr's official `index-no-eval` entry point which strips
all `new Function()` calls at build time, using the interpreted fallback
path instead.

Ref: Effect-TS/effect#6161
bohdanbirdie added a commit to bohdanbirdie/livestore that referenced this pull request Apr 13, 2026
CF Workers blocks `new Function()` during request handling (CSP).
msgpackr's default build uses JIT code generation via `new Function()`
when decoding 4+ same-structure objects in a single unpackMultiple call.
This causes @effect/rpc's msgPack serialization to silently return empty
responses on deployed CF Workers.

Switch to msgpackr's official `index-no-eval` entry point which strips
all `new Function()` calls at build time, using the interpreted fallback
path instead.

Ref: Effect-TS/effect#6161
bohdanbirdie added a commit to bohdanbirdie/livestore that referenced this pull request Apr 13, 2026
CF Workers blocks `new Function()` during request handling (CSP).
msgpackr's default build uses JIT code generation via `new Function()`
when decoding 4+ same-structure objects in a single unpackMultiple call.
This causes @effect/rpc's msgPack serialization to silently return empty
responses on deployed CF Workers.

Switch to msgpackr's official `index-no-eval` entry point which strips
all `new Function()` calls at build time, using the interpreted fallback
path instead.

Ref: Effect-TS/effect#6161
IGassmann added a commit to livestorejs/livestore that referenced this pull request Apr 13, 2026
…ers (#1163)

CF Workers blocks `new Function()` during request handling (CSP).
msgpackr's default build uses JIT code generation via `new Function()`
when decoding 4+ same-structure objects in a single unpackMultiple call.
This causes @effect/rpc's msgPack serialization to silently return empty
responses on deployed CF Workers.

Switch to msgpackr's official `index-no-eval` entry point which strips
all `new Function()` calls at build time, using the interpreted fallback
path instead.

Ref: Effect-TS/effect#6161

Co-authored-by: Igor Gassmann <igor@igassmann.me>
@IGassmann
Copy link
Copy Markdown
Contributor

IGassmann commented Apr 15, 2026

FYI, msgpackr has landed an upstream fix that wraps the new Function() call in a try/catch, falling back to the interpreted path when it's blocked. Once that's released and @effect/rpc updates its msgpackr dependency, this would fix #6169 without needing { useRecords: false }.

That said, the configurable makeMsgPack(options) API and the decode error-swallowing fix in this PR are still valuable independently.

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 5a7e0d4 to d7c7cfa Compare April 18, 2026 09:27
@IGassmann
Copy link
Copy Markdown
Contributor

The upstream fix has been released in msgpackr 1.11.10 (see kriszyp/msgpackr#179). I've opened #6191 to bump the minimum msgpackr version to ^1.11.10, which resolves the Cloudflare Workers issue without needing configurable options or the no-eval entry point.

@tim-smart tim-smart enabled auto-merge (squash) April 22, 2026 22:43
@tim-smart tim-smart disabled auto-merge April 22, 2026 22:44
@tim-smart tim-smart enabled auto-merge (squash) April 22, 2026 22:44
@tim-smart tim-smart merged commit e2374c2 into Effect-TS:main Apr 22, 2026
11 checks passed
@github-project-automation github-project-automation Bot moved this from Discussion Ongoing to Done in PR Backlog Apr 22, 2026
@github-actions github-actions Bot mentioned this pull request Apr 22, 2026
Hoishin added a commit to Hoishin/effect that referenced this pull request May 18, 2026
* upstream/main: (126 commits)
  fix(@effect/cli): use Ansi.blackBright for Weak spans so --help is readable on dark terminals (Effect-TS#6208)
  fix(cli): replace all hyphens in shell completion command names (Effect-TS#6213)
  Version Packages (Effect-TS#6218)
  Support null K8s lastTransitionTime values (Effect-TS#6217)
  Version Packages (Effect-TS#6197)
  Backport workflow suspension failure fixes (Effect-TS#6196)
  clone full v4 history
  Version Packages (Effect-TS#6195)
  preserve fiber context in HttpLayerRouter.addHttpApi so API-level middleware is applied (Effect-TS#6147)
  correct typos in source code (receive, separate) (Effect-TS#6110)
  docs(@effect/vitest): fix return type in fails example (Effect-TS#6163)
  make RpcSerialization.msgPack options configurable (Effect-TS#6161)
  update msgpackr to 1.11.10 for Cloudflare Workers compatibility (Effect-TS#6191)
  fix: floor TestClock nanoseconds before BigInt conversion (Effect-TS#6194)
  chore: disable TypeScript's nightly workflow (Effect-TS#6193)
  Version Packages (Effect-TS#6189)
  (fix: ai-openai) Remove strict param from the OpenAI request body (Effect-TS#6188)
  Version Packages (Effect-TS#6142)
  fix(ai-openai): deduplicate response.output items to prevent invalid JSON concatenation (Effect-TS#6178)
  Change 'in-memory' to 'in_memory' in prompt cache enums (Effect-TS#6187)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Bug: RpcSerialization.msgPack silently swallows decode errors

3 participants