refactor: replace HTTP status code checks with semantic error types#1342
refactor: replace HTTP status code checks with semantic error types#1342pranaygp wants to merge 1 commit intopgp/run-failed-schema-vailidation-errorfrom
Conversation
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests🐘 Local Postgres (1 failed)fastify-stable (1 failed):
🌍 Community Worlds (56 failed)mongodb (3 failed):
redis (2 failed):
turso (51 failed):
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
❌ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
✅ 📋 Other
❌ Some E2E test jobs failed:
Check the workflow run for details. |
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
8480225 to
6655edc
Compare
1563db7 to
2841381
Compare
🦋 Changeset detectedLatest commit: cb18ce3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 20 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 |
🦋 Changeset detectedLatest commit: 2841381 The changes in this PR will be included in the next version bump. This PR includes changesets to release 20 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 |
e7068bf to
e019085
Compare
90bd273 to
0a9c6f7
Compare
256bb01 to
1f26e4e
Compare
…runtime Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0a9c6f7 to
cb18ce3
Compare
There was a problem hiding this comment.
Pull request overview
Refactors error handling across the core runtime and world implementations to replace runtime-side HTTP status code branching (409/410/429) with semantic error types emitted by worlds, reducing coupling to HTTP transport details.
Changes:
- Add new semantic error classes in
@workflow/errors:EntityConflictError,RunExpiredError,ThrottleError. - Update
world-vercelto map HTTP 409/410/429 to those semantic errors at the request boundary. - Update
world-local,world-postgres, and@workflow/coreruntime call sites to throw/catch semantic errors instead ofWorkflowAPIError.status.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/world-vercel/src/utils.ts | Map HTTP 409/410/429 responses to semantic errors in makeRequest() |
| packages/world-postgres/src/storage.ts | Replace storage-layer WorkflowAPIError({status:409/410}) with semantic errors |
| packages/world-local/src/storage/events-storage.ts | Replace local storage WorkflowAPIError({status:409/410}) with semantic errors |
| packages/world-local/src/fs.ts | Use EntityConflictError for write conflicts instead of HTTP-encoded errors |
| packages/errors/src/index.ts | Introduce semantic error classes for conflict/expired/throttle cases |
| packages/core/src/runtime/suspension-handler.ts | Replace runtime checks for 409/410 with semantic errors in suspension flow |
| packages/core/src/runtime/step-handler.ts | Replace runtime checks for 409/410/429 with semantic errors in step processing |
| packages/core/src/runtime/step-handler.test.ts | Update tests to throw EntityConflictError instead of WorkflowAPIError(409) |
| packages/core/src/runtime/runs.ts | Use EntityConflictError for wake-up conflict handling |
| packages/core/src/runtime/runs.test.ts | Update tests to use EntityConflictError |
| packages/core/src/runtime.ts | Replace runtime status checks (409/410) with semantic error guards |
| .changeset/semantic-world-errors.md | Publish patch bumps for affected packages |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| * Thrown when attempting to operate on a run that has been cleaned up or expired. | ||
| * Replaces WorkflowAPIError with status 410. |
| // 425 Too Early: retryAfter timestamp not reached yet | ||
| // Return timeout to queue so it retries later | ||
| if (WorkflowAPIError.is(err) && err.status === 425) { | ||
| // Parse retryAfter from error response meta |
| } else if (WorkflowAPIError.is(err) && err.status === 404) { | ||
| // Hook may have already been disposed or never created | ||
| runtimeLogger.info('Hook not found for disposal, continuing', { | ||
| workflowRunId: runId, | ||
| correlationId: queueItem.correlationId, | ||
| message: err.message, | ||
| }); |
| } | ||
|
|
||
| /** | ||
| * Thrown when attempting to modify an entity that is already in a terminal state. |

Summary
Replaces the pattern of catching
WorkflowAPIErrorwith HTTP status codes (409,410,429) in the runtime with semantic error types that each world implementation throws directly. This removes the coupling between the runtime and HTTP transport semantics.Stacked on #1340 → #1339
Problem
The runtime had ~18 places doing this:
This is wrong because:
world-vercelimplementation detail leaking into the runtimeworld-localandworld-postgreshad to fake HTTP status codes (new WorkflowAPIError('...', { status: 409 })) to matchSolution
New semantic error types (
@workflow/errors)EntityConflictErrorstatus === 409RunExpiredErrorstatus === 410ThrottleErrorstatus === 429retryAfterAll follow the existing
HookNotFoundError/WorkflowRunNotFoundErrorpattern with.is()static method.World implementations updated
makeRequest()maps HTTP 409 →EntityConflictError, 410 →RunExpiredError, 429 →ThrottleErrorat the throw siteWorkflowAPIError({ status: 409 })→EntityConflictError, etc.Runtime updated
All ~18 catch sites now use semantic checks:
Files touched:
runtime.ts,step-handler.ts,suspension-handler.ts,helpers.ts,runs.tsWorkflowAPIErrorretained as catch-allWorkflowAPIErrorremains for genuinely unexpected HTTP errors. The runtime no longer inspects.statuson it.Test plan
helpers.test.ts,step-handler.test.ts,runs.test.ts🤖 Generated with Claude Code