fix: prioritize custom class serialization over generic Error serialization#1172
Conversation
…zation Move the Instance and Class reducers before the Error reducer in getCommonReducers() so that Error subclasses implementing WORKFLOW_SERIALIZE are serialized using custom class serialization instead of the generic Error reducer. devalue uses first-match-wins, so the previous ordering caused custom Error subclasses to lose their custom fields (only name/message/stack were preserved).
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests🌍 Community Worlds (45 failed)turso (45 failed):
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
✅ 📋 Other
|
🦋 Changeset detectedLatest commit: 0d34afb The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
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 |
📊 Benchmark Results
workflow with no steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express workflow with 1 step💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro workflow with 10 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 25 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 50 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.all with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro Promise.all with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro Promise.all with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro Promise.race with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Promise.race with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Promise.race with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical serialization bug where custom Error subclasses implementing WORKFLOW_SERIALIZE were losing their custom fields due to incorrect reducer ordering. The fix leverages devalue's first-match-wins strategy by moving the Instance and Class reducers before the Error reducer in getCommonReducers(), ensuring custom Error serialization takes precedence over the generic Error serialization that only preserves name, message, and stack.
Changes:
- Relocated
InstanceandClassreducers to appear beforeErrorreducer in serialization order - Added 5 comprehensive unit tests covering custom Error subclass serialization across different code paths
- Added changeset documenting the patch-level fix
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/core/src/serialization.ts | Moved Instance and Class reducers before Error reducer to fix serialization precedence for custom Error subclasses |
| packages/core/src/serialization.test.ts | Added 5 new tests verifying custom Error serialization, plain Error handling, and edge cases |
| .changeset/custom-error-serde-precedence.md | Documented the patch-level bug fix |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
InstanceandClassreducers before theErrorreducer ingetCommonReducers()so that custom Error subclasses implementingWORKFLOW_SERIALIZEare serialized via theInstancereducer instead of the genericErrorreducer.devalueuses a first-match-wins strategy when iterating reducers, so the previous ordering caused custom Error subclasses to silently lose their custom fields — onlyname,message, andstackwere preserved.WORKFLOW_SERIALIZEstill use the generic Error reducer.