Skip to content

feat: export semantic error types and add API reference docs - #1447

Merged
pranaygp merged 9 commits into
mainfrom
pgp/error-docs
Mar 24, 2026
Merged

feat: export semantic error types and add API reference docs#1447
pranaygp merged 9 commits into
mainfrom
pgp/error-docs

Conversation

@pranaygp

Copy link
Copy Markdown
Contributor

Summary

  • Re-export all semantic error types (HookNotFoundError, EntityConflictError, RunExpiredError, TooEarlyError, ThrottleError, RunNotSupportedError, WorkflowWorldError) from workflow/internal/errors
  • Add new error classes to @workflow/errors: WorkflowWorldError, EntityConflictError, RunExpiredError, TooEarlyError, ThrottleError (world-level semantic errors)
  • Tighten TSDoc comments on all error classes with consistent format (when thrown, how to handle, .is() method, key properties)
  • Add API reference documentation for 9 error types organized by tier (user-facing, infrastructure, world-internal)

Test plan

  • pnpm build passes
  • pnpm typecheck passes
  • Verify docs render correctly in local dev server
  • Verify workflow/internal/errors exports are accessible at runtime

🤖 Generated with Claude Code

@pranaygp
pranaygp requested a review from a team as a code ownerMarch 18, 2026 21:56
CopilotAI review requested due to automatic review settings March 18, 2026 21:56
@vercel

vercelBot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Mar 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7afb73d

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

This PR includes changesets to release 20 packages
NameType
workflowPatch
@workflow/errorsPatch
@workflow/aiPatch
@workflow/world-testingPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/corePatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/world-vercelPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/vitestPatch
@workflow/web-sharedPatch
@workflow/nuxtPatch

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the public surface area and documentation around semantic error types by re-exporting them via workflow/internal/errors, adding/standardizing world-level error classes in @workflow/errors, and introducing API reference docs for these errors. It also adds DEBUG-gated request timing logs in the Vercel world client and fixes a CLI env var passthrough.

Changes:

  • Re-export semantic error types from workflow/internal/errors and add new world-level semantic error classes to @workflow/errors.
  • Add/standardize TSDoc on error classes and add API reference docs pages for the error types.
  • Add DEBUG-gated HTTP timing logs in @workflow/world-vercel and pass WORKFLOW_LOCAL_BASE_URL through CLI inspect env.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/world-vercel/src/utils.tsAdds lightweight DEBUG-gated HTTP timing logging around fetch() requests.
packages/workflow/src/internal/errors.tsRe-exports semantic/world error types from @workflow/errors via workflow/internal/errors.
packages/errors/src/index.tsAdds/extends semantic error classes (world-level) and improves TSDoc consistency/examples.
packages/core/src/runtime/helpers.tsAdds runtime debug logs for event pagination load timing during replay.
packages/cli/src/lib/inspect/env.tsIncludes WORKFLOW_LOCAL_BASE_URL in env var collection for inspect/health checks.
docs/content/docs/api-reference/workflow/workflow-world-error.mdxNew API reference page for WorkflowWorldError.
docs/content/docs/api-reference/workflow/workflow-run-not-found-error.mdxNew API reference page for WorkflowRunNotFoundError.
docs/content/docs/api-reference/workflow/workflow-run-failed-error.mdxNew API reference page for WorkflowRunFailedError.
docs/content/docs/api-reference/workflow/workflow-run-cancelled-error.mdxNew API reference page for WorkflowRunCancelledError.
docs/content/docs/api-reference/workflow/too-early-error.mdxNew API reference page for TooEarlyError.
docs/content/docs/api-reference/workflow/throttle-error.mdxNew API reference page for ThrottleError.
docs/content/docs/api-reference/workflow/run-expired-error.mdxNew API reference page for RunExpiredError.
docs/content/docs/api-reference/workflow/hook-not-found-error.mdxNew API reference page for HookNotFoundError.
docs/content/docs/api-reference/workflow/entity-conflict-error.mdxNew API reference page for EntityConflictError.
docs/content/docs/api-reference/workflow/meta.jsonAdds new error reference pages to the workflow API reference sidebar.
.changeset/error-docs-and-exports.mdChangeset for workflow + @workflow/errors export/doc updates.
.changeset/early-bats-make.mdChangeset for @workflow/world-vercel DEBUG HTTP timing logs.
.changeset/bumpy-mice-do.mdChangeset for @workflow/cli env var passthrough fix.

💡 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.

Comment threadpackages/world-vercel/src/utils.ts Outdated
Comment on lines 9 to 34

/**
* Lightweight debug logger for HTTP requests. Activated when the DEBUG
* env var includes "workflow:" (matching the standard `debug` module
* convention used by @workflow/core).
*/
const HTTP_DEBUG_ENABLED =
typeof process !== 'undefined' &&
typeof process.env.DEBUG === 'string' &&
(process.env.DEBUG.includes('workflow:') || process.env.DEBUG === '*');

function httpLog(
method: string,
endpoint: string,
status: number,
ms: number
): void {
if (HTTP_DEBUG_ENABLED) {
console.debug(
`[workflow:world-vercel:http] ${method} ${endpoint} -> ${status} (${ms}ms)`
);
}
}
import {
ErrorType,
getSpanKind,
Comment on lines +10 to +18
/**
* Lightweight debug logger for HTTP requests. Activated when the DEBUG
* env var includes "workflow:" (matching the standard `debug` module
* convention used by @workflow/core).
*/
const HTTP_DEBUG_ENABLED =
typeof process !== 'undefined' &&
typeof process.env.DEBUG === 'string' &&
(process.env.DEBUG.includes('workflow:') || process.env.DEBUG === '*');

@karthikscale3karthikscale3Mar 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a correct suggestion

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — the current check is intentionally lightweight and doesn't implement full debug glob/negation semantics. It covers the common cases (DEBUG=workflow:* and DEBUG=*). I've updated the JSDoc comment to say "Activated when the DEBUG env var contains workflow: or is *" to avoid implying full debug module compatibility. A full implementation would add complexity for a debug-only logger.

@pranaygp
pranaygp marked this pull request as draft March 18, 2026 22:05
Base automatically changed from pgp/semantic-world-errors to mainMarch 18, 2026 22:07
@github-actions

github-actionsBot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro0.037s (-3.9%)1.005s (~)0.969s101.00x
💻 LocalExpress0.042s (-9.1% 🟢)1.005s (~)0.963s101.14x
🐘 PostgresNitro0.064s (-8.5% 🟢)1.012s (~)0.948s101.74x
🐘 PostgresExpress0.065s (+16.7% 🔺)1.011s (~)0.946s101.77x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.481s (-27.2% 🟢)2.574s (+7.7% 🔺)2.093s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.095s (~)2.006s (~)0.912s101.00x
💻 LocalExpress1.125s (~)2.005s (~)0.880s101.03x
🐘 PostgresExpress1.148s (~)2.013s (~)0.865s101.05x
🐘 PostgresNitro1.149s (-1.2%)2.009s (~)0.860s101.05x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.060s (~)3.724s (+1.6%)1.664s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro10.618s (~)11.023s (~)0.406s31.00x
🐘 PostgresNitro10.887s (-2.3%)11.025s (-8.5% 🟢)0.137s31.03x
💻 LocalExpress10.894s (-0.6%)11.022s (~)0.128s31.03x
🐘 PostgresExpress10.946s (~)11.020s (~)0.074s31.03x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)18.197s (+5.7% 🔺)20.379s (+7.0% 🔺)2.183s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro14.194s (~)15.028s (~)0.833s41.00x
🐘 PostgresNitro14.598s (-2.0%)15.030s (~)0.433s41.03x
🐘 PostgresExpress14.599s (-1.5%)15.029s (~)0.430s41.03x
💻 LocalExpress14.889s (-0.9%)15.027s (-4.8%)0.137s41.05x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)33.828s (+0.6%)35.288s (+1.3%)1.461s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.993s (-5.8% 🟢)14.451s (-5.0%)0.458s71.00x
🐘 PostgresExpress14.013s (-2.9%)14.308s (-4.9%)0.294s71.00x
💻 LocalNitro14.786s (-0.6%)15.029s (~)0.243s61.06x
💻 LocalExpress16.424s (-3.6%)17.028s (-1.9%)0.604s61.17x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)66.695s (+9.0% 🔺)68.311s (+9.2% 🔺)1.615s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.257s (-2.0%)2.012s (~)0.754s151.00x
🐘 PostgresNitro1.278s (-1.7%)2.013s (~)0.734s151.02x
💻 LocalNitro1.457s (~)2.005s (~)0.549s151.16x
💻 LocalExpress1.509s (-1.4%)2.005s (~)0.496s151.20x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.583s (~)4.208s (+2.6%)1.625s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.315s (-7.2% 🟢)3.010s (~)0.695s101.00x
🐘 PostgresExpress2.408s (-1.4%)3.109s (+3.2%)0.701s101.04x
💻 LocalNitro2.586s (+2.3%)3.007s (~)0.422s101.12x
💻 LocalExpress2.985s (-3.7%)3.453s (-13.9% 🟢)0.468s91.29x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (+8.1% 🔺)4.518s (+5.4% 🔺)1.343s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro3.473s (-5.3% 🟢)4.014s (~)0.540s81.00x
🐘 PostgresExpress3.486s (-2.3%)4.014s (~)0.528s81.00x
💻 LocalNitro6.635s (-0.7%)7.018s (~)0.383s51.91x
💻 LocalExpress7.967s (-8.6% 🟢)8.768s (-5.4% 🟢)0.801s42.29x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)4.105s (-1.4%)5.526s (-0.5%)1.421s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.259s (-2.5%)2.011s (~)0.752s151.00x
🐘 PostgresNitro1.261s (-2.3%)2.011s (~)0.750s151.00x
💻 LocalNitro1.467s (~)2.005s (~)0.538s151.17x
💻 LocalExpress1.559s (+1.0%)2.006s (~)0.447s151.24x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.973s (+15.0% 🔺)4.623s (+22.3% 🔺)1.650s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.325s (-6.8% 🟢)3.011s (~)0.686s101.00x
🐘 PostgresExpress2.337s (-4.7%)3.011s (~)0.674s101.01x
💻 LocalNitro2.786s (-2.8%)3.108s (~)0.322s101.20x
💻 LocalExpress2.950s (-7.0% 🟢)3.676s (-8.3% 🟢)0.726s91.27x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.226s (+7.6% 🔺)5.083s (+18.5% 🔺)1.857s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.454s (-4.0%)4.012s (~)0.558s81.00x
🐘 PostgresNitro3.493s (-4.3%)4.012s (~)0.520s81.01x
💻 LocalNitro7.473s (+1.1%)8.017s (~)0.545s42.16x
💻 LocalExpress8.704s (-4.9%)9.022s (-10.0% 🟢)0.318s42.52x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)4.085s (+13.9% 🔺)6.307s (+28.1% 🔺)2.222s51.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro0.676s (~)1.004s (~)0.328s601.00x
🐘 PostgresExpress0.820s (-10.4% 🟢)1.007s (-6.7% 🟢)0.187s601.21x
🐘 PostgresNitro0.839s (-13.4% 🟢)1.024s (-17.1% 🟢)0.185s591.24x
💻 LocalExpress0.968s (-4.3%)1.116s (-27.7% 🟢)0.148s541.43x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)10.852s (+9.2% 🔺)12.523s (+1.3%)1.671s51.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.915s (-14.0% 🟢)2.054s (-31.8% 🟢)0.139s441.00x
🐘 PostgresNitro1.950s (-15.6% 🟢)2.253s (-25.2% 🟢)0.303s411.02x
💻 LocalNitro2.220s (+1.3%)3.007s (~)0.787s301.16x
💻 LocalExpress2.959s (-2.5%)3.107s (-15.8% 🟢)0.149s301.55x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.025s (+4.9%)35.659s (+6.0% 🔺)1.634s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.919s (-12.8% 🟢)4.217s (-15.9% 🟢)0.298s291.00x
🐘 PostgresNitro3.997s (-16.5% 🟢)4.405s (-13.6% 🟢)0.407s281.02x
💻 LocalNitro7.252s (~)8.014s (~)0.762s151.85x
💻 LocalExpress9.050s (+2.7%)9.556s (+4.3%)0.506s132.31x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)98.599s (+14.5% 🔺)100.525s (+13.6% 🔺)1.926s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.281s (-5.1% 🟢)1.009s (~)0.727s601.00x
🐘 PostgresNitro0.284s (-10.4% 🟢)1.008s (~)0.724s601.01x
💻 LocalNitro0.591s (+5.3% 🔺)1.021s (+1.7%)0.431s592.10x
💻 LocalExpress0.596s (+4.8%)1.004s (~)0.409s602.12x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.117s (+11.9% 🔺)4.018s (+7.1% 🔺)1.901s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.497s (-9.2% 🟢)1.008s (~)0.511s901.00x
🐘 PostgresNitro0.507s (-13.1% 🟢)1.008s (~)0.501s901.02x
💻 LocalNitro2.312s (-1.4%)3.007s (~)0.695s304.65x
💻 LocalExpress2.534s (+3.3%)3.009s (~)0.475s305.10x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.899s (+20.2% 🔺)5.521s (+16.9% 🔺)1.622s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.791s (-13.9% 🟢)1.026s (-17.2% 🟢)0.235s1171.00x
🐘 PostgresNitro0.811s (-16.2% 🟢)1.010s (-27.8% 🟢)0.199s1191.02x
💻 LocalNitro9.975s (~)10.440s (+0.8%)0.465s1212.61x
💻 LocalExpress11.196s (+1.6%)11.847s (+1.5%)0.651s1114.15x
💻 LocalNext.js (Turbopack)⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)7.531s (-76.5% 🟢)9.113s (-73.0% 🟢)1.582s141.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro0.135s (-3.0%)1.003s (~)0.009s (-5.2% 🟢)1.015s (~)0.880s101.00x
💻 LocalExpress0.201s (-2.6%)1.003s (~)0.012s (~)1.018s (~)0.816s101.49x
🐘 PostgresNitro0.203s (-15.3% 🟢)0.994s (~)0.001s (-27.8% 🟢)1.010s (~)0.807s101.51x
🐘 PostgresExpress0.205s (-7.9% 🟢)0.997s (~)0.001s (~)1.010s (~)0.805s101.52x
💻 LocalNext.js (Turbopack)⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.805s (+10.3% 🔺)2.939s (+0.7%)0.522s (+30.8% 🔺)4.136s (+6.8% 🔺)2.331s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro0.564s (-0.6%)1.009s (~)0.009s (-3.7%)1.023s (~)0.459s591.00x
🐘 PostgresExpress0.620s (-11.8% 🟢)1.002s (~)0.004s (-36.2% 🟢)1.024s (-0.8%)0.404s591.10x
🐘 PostgresNitro0.625s (-13.8% 🟢)1.003s (~)0.004s (-25.1% 🟢)1.024s (-0.6%)0.399s591.11x
💻 LocalExpress0.721s (~)1.010s (~)0.010s (+5.8% 🔺)1.023s (~)0.302s591.28x
💻 LocalNext.js (Turbopack)⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)7.899s (+73.0% 🔺)9.301s (+66.4% 🔺)0.153s (-31.7% 🟢)10.208s (+57.9% 🔺)2.308s61.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.978s (-12.8% 🟢)1.269s (-28.7% 🟢)0.000s (-63.8% 🟢)1.286s (-29.0% 🟢)0.307s471.00x
🐘 PostgresNitro1.009s (-13.7% 🟢)1.387s (-30.5% 🟢)0.000s (+4.7%)1.415s (-30.0% 🟢)0.406s431.03x
💻 LocalNitro1.135s (~)2.017s (~)0.000s (+12.5% 🔺)2.020s (~)0.886s301.16x
💻 LocalExpress1.218s (+1.2%)2.020s (~)0.000s (~)2.023s (~)0.805s301.24x
💻 LocalNext.js (Turbopack)⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.895s (+10.6% 🔺)5.069s (+9.0% 🔺)0.000s (NaN%)5.738s (+10.2% 🔺)1.843s111.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.715s (-24.3% 🟢)2.105s (-28.7% 🟢)0.000s (-100.0% 🟢)2.144s (-27.8% 🟢)0.429s281.00x
🐘 PostgresExpress1.803s (-12.4% 🟢)2.139s (-13.7% 🟢)0.000s (+Infinity% 🔺)2.153s (-13.9% 🟢)0.350s281.05x
💻 LocalNitro3.489s (+0.9%)3.968s (-1.6%)0.001s (+8.2% 🔺)3.973s (-1.5%)0.484s162.03x
💻 LocalExpress3.500s (+3.2%)4.032s (-1.6%)0.000s (+150.0% 🔺)4.035s (-1.6%)0.535s152.04x
💻 LocalNext.js (Turbopack)⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)4.366s (-2.4%)5.698s (+5.2% 🔺)0.000s (+230.0% 🔺)6.332s (+6.5% 🔺)1.966s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNitro21/21
🐘 PostgresExpress12/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres17/21
Next.js (Turbopack)▲ Vercel21/21
Nitro🐘 Postgres14/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@github-actions

github-actionsBot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production780067847
✅ 💻 Local Development7820142924
✅ 📦 Local Production7820142924
✅ 🐘 Local Postgres7820142924
✅ 🪟 Windows720577
❌ 🌍 Community Worlds1185621195
✅ 📋 Other198033231
Total3514565524122

❌ Failed Tests

🌍 Community Worlds (56 failed)

mongodb (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KMEHV990FWF12VTER4TND1XN
  • webhookWorkflow | wrun_01KMEHVJHCDZCCWFA3SMNDXCDW
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KMEJ1Z3PG4TXZB85Q6WJQD23

redis (2 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KMEHV990FWF12VTER4TND1XN
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KMEJ1Z3PG4TXZB85Q6WJQD23

turso (51 failed):

  • addTenWorkflow | wrun_01KMEHT1YR6TAPD186MJ0SZXR8
  • addTenWorkflow | wrun_01KMEHT1YR6TAPD186MJ0SZXR8
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KMEHV8CZK91ZX4P9P8X6WGAY
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KMEHT91YHDBNDDXKQC0AWQPJ
  • promiseRaceWorkflow | wrun_01KMEHTDT2EKPJ28PG3AFCYFDJ
  • promiseAnyWorkflow | wrun_01KMEHTJD87WXV9WMX5BVFX360
  • importedStepOnlyWorkflow | wrun_01KMEHVK5K9YP8MSG7SRYCKN1C
  • hookWorkflow | wrun_01KMEHTZ3TT3RDMRVZJP02JX4A
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KMEHV990FWF12VTER4TND1XN
  • webhookWorkflow | wrun_01KMEHVJHCDZCCWFA3SMNDXCDW
  • sleepingWorkflow | wrun_01KMEHVS363CSKSQS8S22H96SM
  • parallelSleepWorkflow | wrun_01KMEHW5VJ79Y76X0D7HZB5M9Q
  • nullByteWorkflow | wrun_01KMEHWACXSX9NQRH7DW9NDXBZ
  • workflowAndStepMetadataWorkflow | wrun_01KMEHWCPZA4DWHA4BKT2JSCFW
  • fetchWorkflow | wrun_01KMEHY681WDC5ECQJV8R3E3Z3
  • promiseRaceStressTestWorkflow | wrun_01KMEHY9Q3HD75MW1BCZXQQVT5
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KMEJ1AM5M5PEM0PC8G25F177
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KMEJ1Z3PG4TXZB85Q6WJQD23
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KMEJ2QKZR9PAKCV62F5H0D9D
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KMEJ3D0P2GT90HR31R98RNAR
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KMEJ3P5P7N9E6KP0X4DJVX38
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KMEJ3VTHT0VG2VV04Y0VA7SG
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KMEJ3Y4BD3Z2T8MKPH3H1DNZ
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KMEJ4DY63N9K1MBQR3V8V96M
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KMEJ4KQ98X46MX3W710A9C92
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KMEJ4TJ3CF904A56BZTCGKF0
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KMEJ50D0ECZ08HN8YMGY3R9J
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KMEJ5764BJ0C6KTACDZRZHYY
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KMEJ5E07JT8WFC4DZGBWZDGR
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KMEJ5MSV8WYD4FM4NBE40XW3
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KMEJ5Z0YDZ0DHC0WY1C4AQ83
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KMEJ6739XYJTV7MPEZGQN2R0
  • cancelRun - cancelling a running workflow | wrun_01KMEJ6E6636CGSXC3AKQBFZVT
  • cancelRun via CLI - cancelling a running workflow | wrun_01KMEJ6QKAX0D4YWD2G110767T
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep | wrun_01KMEJ73VCQ8V5ZX5AS70BA6J9
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KMEJ7RPDPAJCYFDX6K8XSK59
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KMEJ8354AG2P0EXKPSCWQH35

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro7007
✅ example7007
✅ express7007
✅ fastify7007
✅ hono7007
✅ nextjs-turbopack7502
✅ nextjs-webpack7502
✅ nitro7007
✅ nuxt7007
✅ sveltekit7007
✅ vite7007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable66011
✅ express-stable66011
✅ fastify-stable66011
✅ hono-stable66011
✅ nextjs-turbopack-canary55022
✅ nextjs-turbopack-stable7205
✅ nextjs-webpack-canary55022
✅ nextjs-webpack-stable7205
✅ nitro-stable66011
✅ nuxt-stable66011
✅ sveltekit-stable66011
✅ vite-stable66011
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable66011
✅ express-stable66011
✅ fastify-stable66011
✅ hono-stable66011
✅ nextjs-turbopack-canary55022
✅ nextjs-turbopack-stable7205
✅ nextjs-webpack-canary55022
✅ nextjs-webpack-stable7205
✅ nitro-stable66011
✅ nuxt-stable66011
✅ sveltekit-stable66011
✅ vite-stable66011
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable66011
✅ express-stable66011
✅ fastify-stable66011
✅ hono-stable66011
✅ nextjs-turbopack-canary55022
✅ nextjs-turbopack-stable7205
✅ nextjs-webpack-canary55022
✅ nextjs-webpack-stable7205
✅ nitro-stable66011
✅ nuxt-stable66011
✅ sveltekit-stable66011
✅ vite-stable66011
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7205
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev302
❌ mongodb5235
✅ redis-dev302
❌ redis5325
✅ turso-dev302
❌ turso4515
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable66011
✅ e2e-local-postgres-nest-stable66011
✅ e2e-local-prod-nest-stable66011

📋 View full workflow run

- Resolve merge conflict in world-vercel/utils.ts
- Add @skip-typecheck markers to all error API reference docs code
samples that use placeholder variables (world, runId, run, etc.)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
// Return timeout to queue so it retries later
if (TooEarlyError.is(err)) {
const retryAfter = err.retryAfter ?? new Date(Date.now() + 1000);
const retryAfter = err.retryAfterDate ?? new Date(Date.now() + 1000);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this real? does this mean that before this PR the retryAfter was not actually working? or did this PR change the type so that it's now correct?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was introduced by this PR — not a pre-existing bug. On main, TooEarlyError extends WorkflowError (which has no retryAfter property), so the retryAfter?: Date property worked fine.

This PR changes the class hierarchy so TooEarlyError extends WorkflowWorldError, which already has retryAfter?: number (seconds, from HTTP Retry-After header). TypeScript doesn't allow a subclass to narrow a property from number to Date, so I renamed the TooEarlyError property to retryAfterDate to avoid the clash. The semantics are the same — just the property name changed.


{/* @skip-typecheck: incomplete snippet with placeholder variables */}
```typescript lineNumbers
import { ThrottleError } from "workflow/internal/errors"

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use should not import from workflow/internal. it should be workflow/errors directly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — all docs now import from workflow/errors and the export was added to workflow/package.json.

pranaygpand others added 3 commits March 20, 2026 16:28
… section
- Replace @skip-typecheck with proper `declare` + `// @setup` lines
so code samples are typechecked but setup lines hidden from readers
- Add `workflow/errors` export to package.json (public API, replaces
`workflow/internal/errors` in docs)
- Add `workflow/errors` path mapping in docs-typecheck type-checker
- Add HookConflictError to re-export list
- Move all error docs under api-reference/workflow/errors/ subdirectory
- Update all internal cross-references and links
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move semantic error docs to api-reference/workflow-errors/ (matching
the workflow/errors import path, like workflow-api for workflow/api)
- Keep FatalError and RetryableError in api-reference/workflow/ since
they're imported from workflow, not workflow/errors
- Fix all cross-reference links
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* origin/main:
[ai] Add experimental_context to DurableAgentOptions (#1489)
[ai] Expose configured tools on DurableAgent instances (#1488)
fix(builders): catch node builtin usage when entry fields diverge (#1455)
[web-shared] Fix timeline duration format and precision (#1482)
[cli] Add bulk cancel, --status filter, fix step JSON hydration (#1467)
[utils] Re-export parseName utilities and add workflow/observability module (#1453)
[o11y] Polish display when run data has expired (#1438)
Add CommonJS `require()` support for class serialization detection in SWC plugin (#1144)
fix(next): stabilize deferred canary e2e in nextjs workbenches (#1468)
[web] Support legacy newline-delimited stream format in `useStreamReader` (#1473)
Revert "Add support for calling start() inside workflow functions (#1133)" (#1475)

@karthikscale3karthikscale3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. disregard: flagged a few inconsistencies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change retryAfterDate, otherwise LGTM

Comment threadpackages/errors/src/index.ts Outdated
export class TooEarlyError extends WorkflowError {
retryAfter?: Date;
export class TooEarlyError extends WorkflowWorldError {
retryAfterDate?: Date;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All instances of retryAfterDate should actually be retryAfter. We should also modify the TooEarlyError creation in world-vercel to be retryAfter instead of retryAfterDate

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — TooEarlyError.retryAfter is now number (seconds), consistent with ThrottleError and WorkflowWorldError. The world-local and world-postgres construction sites convert the DB Date to seconds, and the step-handler consumer uses the seconds value directly.

…owWorldError
TooEarlyError.retryAfter is now seconds (number) instead of a Date,
consistent with ThrottleError and WorkflowWorldError. The conversion
from seconds to Date is done at the consumer site (step-handler) rather
than at construction time.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@karthikscale3karthikscale3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistencies in PR #1447

1. TooEarlyError.retryAfterDate vs WorkflowWorldError.retryAfter -- name collision on the prototype chain

This is the most significant issue. The PR renames TooEarlyError.retryAfter (a Date) to retryAfterDate, but TooEarlyError now extends WorkflowWorldError, which has its own retryAfter property (a number, in seconds). Since TooEarlyError no longer declares retryAfter, it inheritsWorkflowWorldError.retryAfter: number | undefined on its prototype.

This means a TooEarlyError instance will have both:

  • retryAfterDate?: Date (the new renamed property)
  • retryAfter?: number (inherited from WorkflowWorldError, always undefined since TooEarlyError's constructor calls super(message) without passing options)

This isn't broken per se, but it's confusing and makes TooEarlyError inconsistent with ThrottleError, which also extends WorkflowWorldError and does use retryAfter: number directly. And the inherited retryAfter on TooEarlyError will always be undefined, which is misleading.

2. WorkflowWorldError.is() won't match subclasses

The .is() methods check value.name === 'WorkflowWorldError'. But EntityConflictError, RunExpiredError, TooEarlyError, and ThrottleError all set their own this.name (e.g., 'EntityConflictError'). So:

consterr=newEntityConflictError('conflict');WorkflowWorldError.is(err);// false! name is 'EntityConflictError', not 'WorkflowWorldError'

The docs claim WorkflowWorldError is "the base error class" and you can "catch any world-related error regardless of the specific backend or error type." But WorkflowWorldError.is() won't actually match any of its subclasses. The docs' WorkflowWorldError.is(error) example is misleading -- it will only match errors that were constructed directly as WorkflowWorldError, not EntityConflictError etc.

This was already true before the PR (for ThrottleError etc.), but the PR makes it worse by re-parenting 4 more errors under WorkflowWorldError and adding docs that imply .is() is a catch-all.

3. Docs say retryAfterDate is non-optional, but it's Date | undefined in code

The too-early-error.mdx TSDoc block declares:

retryAfterDate: Date;

But the actual class definition is:

retryAfterDate?: Date;

It's optional. The constructor receives options?: { retryAfter?: Date }, and world-vercel/src/utils.ts only sets it when the Retry-After header is present. If the header is missing, retryAfterDate will be undefined.

4. ThrottleError docs say retryAfter: number is non-optional, but it's number | undefined

Same issue as above -- the throttle-error.mdx TSDoc block shows:

retryAfter: number;

But the actual type is retryAfter?: number.

5. Constructor parameter name mismatch for TooEarlyError

The constructor still takes { retryAfter?: Date } as an option, but stores it as retryAfterDate:

constructor(message: string,options?: {retryAfter?: Date}){// ...this.retryAfterDate=options?.retryAfter;}

All existing call sites pass { retryAfter: someDate } which still works, but this is a confusing API: the input parameter is named retryAfter while the property is retryAfterDate. The constructor option should be renamed too for consistency:

constructor(message: string,options?: {retryAfterDate?: Date})

6. WorkflowWorldError docs TSDoc omits status, code, url, retryAfter properties

The workflow-world-error.mdx TSDoc block only shows message:

interface WorkflowWorldError {
/** The error message. */
message: string;
}

But WorkflowWorldError actually has status?: number, code?: string, url?: string, and retryAfter?: number. These are important for debugging and are set by world-vercel's makeRequest utility. Omitting them from the docs means users won't know they can inspect HTTP status codes on world errors.

7. Minor: world-vercel/src/utils.ts import reordering is unrelated noise

The diff moves telemetry imports to the top of the file and updates the HTTP debug logger JSDoc. These are cosmetic changes bundled into a PR about error type exports and docs. Not a bug, but adds noise to the review.


Summary: The most actionable issues are (1) the inherited retryAfter: number ghost property on TooEarlyError, (2) the WorkflowWorldError.is() not matching subclasses despite the docs implying it should, (3/4) the docs claiming retryAfterDate/retryAfter are required when they're actually optional, and (5) the constructor param name mismatch.

- WorkflowWorldError docs: add status, code, url, retryAfter properties
to TSDoc; clarify that .is() only matches direct instances (not
subclasses); use instanceof in catch-all example
- TooEarlyError/ThrottleError docs: mark retryAfter as optional (?)
to match actual type definitions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pranaygp

Copy link
Copy Markdown
ContributorAuthor

Addressed all items from @karthikscale3's review (#1447 (review)):

1. retryAfterDate ghost property — Already fixed. TooEarlyError.retryAfter is now number (seconds), same type as parent. No rename, no ghost property.

2. WorkflowWorldError.is() vs subclasses — Pre-existing by-design behavior (.is() uses name === for cross-VM safety). Updated docs to clarify: use instanceof WorkflowWorldError to catch all world errors, use subclass-specific .is() for specific types.

3/4. Optional properties shown as required — Fixed. TSDoc now shows retryAfter?: number.

5. Constructor param mismatch — Already fixed by reverting to retryAfter: number everywhere.

6. WorkflowWorldError docs missing properties — Fixed. TSDoc now includes status?, code?, url?, retryAfter?.

7. Import reordering — Acknowledged as cosmetic noise from an earlier review comment.

@ghostghost mentioned this pull request Mar 23, 2026
Sign up for freeto 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.

4 participants

@pranaygp@VaguelySerious@karthikscale3