Skip to content

Friendlier build-time errors: WorkflowBuildError + builders sites#1840

Closed
pranaygp wants to merge 1 commit into
pranaygp/friendlier-errors-phase-7-observabilityfrom
pranaygp/friendlier-errors-phase-8-build-time
Closed

Friendlier build-time errors: WorkflowBuildError + builders sites#1840
pranaygp wants to merge 1 commit into
pranaygp/friendlier-errors-phase-7-observabilityfrom
pranaygp/friendlier-errors-phase-8-build-time

Conversation

@pranaygp
Copy link
Copy Markdown
Contributor

@pranaygp pranaygp commented Apr 23, 2026

Summary

Phase 8 (final) of the friendlier-errors stack — extends the error-quality work from runtime into build-time.

  • Adds WorkflowBuildError in @workflow/errors with an optional hint field (appended after a blank line) and a .is() discriminator.
  • Applies it at user-facing sites in @workflow/builders/base-builder.ts:
    • Failed esbuild phases → hint at the likely fix for the phase
    • Unresolved built-in steps → hint at pnpm install workflow
    • Empty esbuild output → hint that workflow files need "use workflow" / "use step" directives
  • Internal runtime invariants remain plain Error.

Scope note: deliberately kept to @workflow/builders (ESM). Extending WorkflowBuildError into @workflow/next (CJS) needs a dynamic-import bridge similar to the existing eval('import("@workflow/builders")') pattern — can follow up in a separate PR.

Manual test plan

All tests here exercise the build pipeline, not the runtime. Use workbench/nextjs-turbopack and run pnpm build (not pnpm dev).

  • Syntax error in a workflow file → failed esbuild phase:

    // workbench/nextjs-turbopack/app/_workflows/broken.ts
    'use workflow';
    export async function broken(
      this is not valid ts

    Run pnpm build. Expect in build output:

    • WorkflowBuildError with title mentioning the phase (e.g. "Build failed during workflows bundle").
    • A blank line, then hint: Review the esbuild errors above — they come from the workflows bundle. Fix the offending source files and re-run the build.
    • The original esbuild error messages printed before the WorkflowBuildError, not suppressed.
  • Unresolved built-in steps — temporarily rename node_modules/workflow to node_modules/workflow-bak:

    mv node_modules/workflow node_modules/workflow-bak
    cd workbench/nextjs-turbopack && pnpm build
    mv ../../node_modules/workflow-bak ../../node_modules/workflow  # restore

    Expect:

    • WorkflowBuildError: "Failed to resolve built-in steps sources."
    • hint: run \pnpm install workflow` to resolve this issue.`
    • cause: preserves the underlying resolution error.
  • Empty workflow directory — move all your workflow files aside (or create a fresh workspace with none):

    mkdir /tmp/wf-empty && cd /tmp/wf-empty
    # set up minimal package + workflow config with an empty workflows/ dir
    pnpm workflow build

    Or: delete all "use workflow" / "use step" directives from your files. Expect:

    • WorkflowBuildError: "No output files generated from esbuild"
    • hint mentions "use workflow" / "use step" directives.
  • .is() discriminator — in a scratch script:

    import { WorkflowBuildError } from '@workflow/errors';
    const e = new WorkflowBuildError('x', { hint: 'y' });
    console.log(WorkflowBuildError.is(e));   // true
    console.log(WorkflowBuildError.is(new Error('x'))); // false
  • Hint renders below a blank line — verify the hint output appears after a blank line, not jammed onto the title line (visual formatting check).

  • Runtime paths unaffected — run a normal workflow at runtime (pnpm dev and trigger a workflow). Confirm no WorkflowBuildError shows up at runtime; this class should only appear in build output.

Unit tests

  • pnpm --filter @workflow/errors test — 19 total (4 new WorkflowBuildError tests)
  • pnpm --filter @workflow/builders typecheck + test (129 pass)

📚 Friendlier errors stack

Multi-PR initiative inspired by @Schniz's stalled #706:

# PR Phase Summary
1 #1831 Phase 1 + 2 Ansi rendering primitives + context-violation errors
2 #1832 Phase 3 Structured logger metadata; folds in #1812
3 #1836 Phase 4 SerializationError at serialization / stream / encryption boundaries
4 #1837 Phase 5 Presentation-only user vs SDK attribution (describeError)
5 #1838 Phase 6 Consistency pass on remaining bare throw new Error(...) sites
6 #1839 Phase 7 foundation Data-driven describeRunError + public subpath
7 → this PR (#1840) Phase 8 WorkflowBuildError + applications in @workflow/builders
8 #1849 Followups Drop functionName leak, simplify docs framing, redirect stack to user code

Each PR is stacked on the previous one; merge in order.

🤖 Generated with Claude Code

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Apr 24, 2026 1:29am
example-nextjs-workflow-webpack Ready Ready Preview, Comment Apr 24, 2026 1:29am
example-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-astro-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-express-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-fastify-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-hono-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-nitro-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-nuxt-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-sveltekit-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workbench-vite-workflow Ready Ready Preview, Comment Apr 24, 2026 1:29am
workflow-docs Ready Ready Preview, Comment, Open in v0 Apr 24, 2026 1:29am
workflow-swc-playground Ready Ready Preview, Comment Apr 24, 2026 1:29am
workflow-web Ready Ready Preview, Comment Apr 24, 2026 1:29am

Copilot AI review requested due to automatic review settings April 23, 2026 16:54
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 23, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
❌ 💻 Local Development 1052 2 86 1140
✅ 📦 Local Production 1054 0 86 1140
✅ 🐘 Local Postgres 1054 0 86 1140
✅ 🪟 Windows 95 0 0 95
✅ 📋 Other 267 0 18 285
Total 3522 2 276 3800

❌ Failed Tests

💻 Local Development (2 failed)

vite-stable (2 failed):

  • 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

Details by Category

❌ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 89 0 6
✅ express-stable 89 0 6
✅ fastify-stable 89 0 6
✅ hono-stable 89 0 6
✅ nextjs-turbopack-canary 76 0 19
✅ nextjs-turbopack-stable 95 0 0
✅ nextjs-webpack-canary 76 0 19
✅ nextjs-webpack-stable 95 0 0
✅ nitro-stable 89 0 6
✅ nuxt-stable 89 0 6
✅ sveltekit-stable 89 0 6
❌ vite-stable 87 2 6
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 89 0 6
✅ express-stable 89 0 6
✅ fastify-stable 89 0 6
✅ hono-stable 89 0 6
✅ nextjs-turbopack-canary 76 0 19
✅ nextjs-turbopack-stable 95 0 0
✅ nextjs-webpack-canary 76 0 19
✅ nextjs-webpack-stable 95 0 0
✅ nitro-stable 89 0 6
✅ nuxt-stable 89 0 6
✅ sveltekit-stable 89 0 6
✅ vite-stable 89 0 6
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 89 0 6
✅ express-stable 89 0 6
✅ fastify-stable 89 0 6
✅ hono-stable 89 0 6
✅ nextjs-turbopack-canary 76 0 19
✅ nextjs-turbopack-stable 95 0 0
✅ nextjs-webpack-canary 76 0 19
✅ nextjs-webpack-stable 95 0 0
✅ nitro-stable 89 0 6
✅ nuxt-stable 89 0 6
✅ sveltekit-stable 89 0 6
✅ vite-stable 89 0 6
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 95 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 89 0 6
✅ e2e-local-postgres-nest-stable 89 0 6
✅ e2e-local-prod-nest-stable 89 0 6

📋 View full workflow run


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: failure
  • Local Prod: success
  • Local Postgres: success
  • Windows: success

Check the workflow run for details.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 23, 2026

🦋 Changeset detected

Latest commit: efaba3a

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

This PR includes changesets to release 21 packages
Name Type
@workflow/errors Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/core Patch
@workflow/web Patch
workflow Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-vercel Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/vitest Patch
@workflow/world-testing Patch
@workflow/web-shared Patch
@workflow/ai Patch
@workflow/nuxt 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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 extends the “friendlier errors” initiative into build-time by introducing a dedicated WorkflowBuildError (with an optional hint) in @workflow/errors and switching key @workflow/builders failure sites to throw it for more actionable build output.

Changes:

  • Add WorkflowBuildError (with hint and .is() discriminator) to @workflow/errors.
  • Update @workflow/builders to throw WorkflowBuildError for esbuild failures, unresolved built-in steps, and empty esbuild output, including user-action hints.
  • Add tests for WorkflowBuildError and publish a changeset for the patch releases.

Reviewed changes

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

File Description
packages/errors/src/index.ts Adds WorkflowBuildError class and documentation.
packages/errors/src/build-error.test.ts Adds vitest coverage for WorkflowBuildError behavior.
packages/builders/src/base-builder.ts Replaces generic Error throws with WorkflowBuildError + hints at key build failure sites.
.changeset/friendlier-build-errors.md Declares patch releases for @workflow/errors and @workflow/builders.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/builders/src/base-builder.ts Outdated
throw new WorkflowBuildError(
`${chalk.red('Failed to resolve built-in steps sources.')}\n\nCaused by: ${chalk.red(String(err))}`,
{
hint: `${chalk.yellow.bold('hint:')} run \`${chalk.cyan.italic('npm install workflow')}\` to resolve this issue.`,
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

options.hint is stored on the error (and appended to the message). Including a formatted hint: label + Chalk styling inside the hint field makes the hint harder to re-render in other contexts (e.g. structured UI/JSON) and can lead to double “hint:” prefixes. Consider keeping hint as plain text (no label/styling) and applying formatting at the presentation layer (or using @workflow/errors Ansi helpers if appropriate).

Suggested change
hint: `${chalk.yellow.bold('hint:')} run \`${chalk.cyan.italic('npm install workflow')}\` to resolve this issue.`,
hint: 'run `npm install workflow` to resolve this issue.',

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in efaba3ahint is now stored as plain text ('run \pnpm install workflow` to resolve this issue.') without the hint:label or chalk styling. Per the updated JSDoc onWorkflowBuildError`, the rendering layer is responsible for styling + any "hint:" label. I also stripped the chalk wrappers from the message string in the same throw so it renders cleanly in non-TTY contexts (CI logs, structured serialization).

Comment thread packages/errors/src/index.ts Outdated
* by the workflow engine) — `WorkflowBuildError` fires during `pnpm build`,
* `next build`, or equivalent, before any workflow has started executing.
*
* Prefer attaching a short, actionable `hint` (e.g. `run \`npm install workflow\``)
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The JSDoc example for hint uses npm install workflow, but other new/updated text in this PR uses pnpm install workflow. Please align this example with the recommended guidance (or switch to a package-manager-agnostic example) so docs and error hints don’t conflict.

Suggested change
* Prefer attaching a short, actionable `hint` (e.g. `run \`npm install workflow\``)
* Prefer attaching a short, actionable `hint` (e.g. `run \`pnpm install workflow\``)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in efaba3a — JSDoc example now uses pnpm install workflow, matching the test and the actual call site.

Comment on lines +14 to +20
hint: 'run `pnpm install workflow` and try again',
});
expect(err.hint).toBe('run `pnpm install workflow` and try again');
expect(err.message).toMatchInlineSnapshot(`
"Build failed during steps

run \`pnpm install workflow\` and try again"
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

This test uses pnpm install workflow in the sample hint string, while some other new hints/docs in this PR use npm install workflow. If the intent is to be package-manager-agnostic (or to standardize on one), consider updating the test string accordingly so it doesn’t implicitly encode the chosen guidance.

Suggested change
hint: 'run `pnpm install workflow` and try again',
});
expect(err.hint).toBe('run `pnpm install workflow` and try again');
expect(err.message).toMatchInlineSnapshot(`
"Build failed during steps
run \`pnpm install workflow\` and try again"
hint: 'run `npm install workflow` and try again',
});
expect(err.hint).toBe('run `npm install workflow` and try again');
expect(err.message).toMatchInlineSnapshot(`
"Build failed during steps
run \`npm install workflow\` and try again"

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in efaba3a — all three sites (the hint in base-builder.ts, this test, and the WorkflowBuildError JSDoc example in packages/errors/src/index.ts) now use pnpm install workflow.

Comment thread packages/builders/src/base-builder.ts Outdated
throw new WorkflowBuildError(
`${chalk.red('Failed to resolve built-in steps sources.')}\n\nCaused by: ${chalk.red(String(err))}`,
{
hint: `${chalk.yellow.bold('hint:')} run \`${chalk.cyan.italic('npm install workflow')}\` to resolve this issue.`,
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The hint text here hard-codes npm install workflow, but elsewhere in this PR (e.g. WorkflowBuildError docs/tests) the guidance mentions pnpm install workflow. Please standardize the suggested command across the repo (or make it package-manager-agnostic, e.g. “install the workflow package”) to avoid confusing users.

Suggested change
hint: `${chalk.yellow.bold('hint:')} run \`${chalk.cyan.italic('npm install workflow')}\` to resolve this issue.`,
hint: `${chalk.yellow.bold('hint:')} install the \`${chalk.cyan.italic('workflow')}\` package to resolve this issue.`,

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in efaba3a — the hint now reads run \pnpm install workflow` to resolve this issue.` (standardized on pnpm across the hint string, the test, and the JSDoc example).

Add `WorkflowBuildError` class in `@workflow/errors` with optional `hint`
for an actionable next step, and apply it in `@workflow/builders` at
user-facing sites: failed esbuild phases, unresolved built-in steps, and
empty esbuild output now throw `WorkflowBuildError` with a hint pointing
at the likely fix. Runtime invariants remain plain `Error`.
@pranaygp
Copy link
Copy Markdown
Contributor Author

Superseded by #1849 — consolidated friendlier-errors PR with all 8 phases + follow-up fixes (ANSI leak, non-retry semantics, shared captureStackTrace helper).

@pranaygp pranaygp closed this Apr 24, 2026
Sign up for free to 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.

2 participants