Friendlier build-time errors: WorkflowBuildError + builders sites#1840
Conversation
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests💻 Local Development (2 failed)vite-stable (2 failed):
Details by Category❌ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
✅ 📋 Other
❌ Some E2E test jobs failed:
Check the workflow run for details. |
🦋 Changeset detectedLatest commit: efaba3a The changes in this PR will be included in the next version bump. This PR includes changesets to release 21 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 |
There was a problem hiding this comment.
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(withhintand.is()discriminator) to@workflow/errors. - Update
@workflow/buildersto throwWorkflowBuildErrorfor esbuild failures, unresolved built-in steps, and empty esbuild output, including user-action hints. - Add tests for
WorkflowBuildErrorand 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.
| 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.`, |
There was a problem hiding this comment.
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).
| 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.', |
There was a problem hiding this comment.
Fixed in efaba3a — hint 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).
| * 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\``) |
There was a problem hiding this comment.
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.
| * Prefer attaching a short, actionable `hint` (e.g. `run \`npm install workflow\``) | |
| * Prefer attaching a short, actionable `hint` (e.g. `run \`pnpm install workflow\``) |
There was a problem hiding this comment.
Fixed in efaba3a — JSDoc example now uses pnpm install workflow, matching the test and the actual call site.
| 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" |
There was a problem hiding this comment.
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.
| 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" |
There was a problem hiding this comment.
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.
| 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.`, |
There was a problem hiding this comment.
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.
| 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.`, |
There was a problem hiding this comment.
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).
ff48e25 to
e6b8e31
Compare
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`.
cb4bbc0 to
efaba3a
Compare
|
Superseded by #1849 — consolidated friendlier-errors PR with all 8 phases + follow-up fixes (ANSI leak, non-retry semantics, shared captureStackTrace helper). |
Summary
Phase 8 (final) of the friendlier-errors stack — extends the error-quality work from runtime into build-time.
WorkflowBuildErrorin@workflow/errorswith an optionalhintfield (appended after a blank line) and a.is()discriminator.@workflow/builders/base-builder.ts:pnpm install workflow"use workflow"/"use step"directivesError.Scope note: deliberately kept to
@workflow/builders(ESM). ExtendingWorkflowBuildErrorinto@workflow/next(CJS) needs a dynamic-import bridge similar to the existingeval('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-turbopackand runpnpm build(notpnpm dev).Syntax error in a workflow file → failed esbuild phase:
Run
pnpm build. Expect in build output:WorkflowBuildErrorwith title mentioning the phase (e.g. "Build failed during workflows bundle").hint: Review the esbuild errors above — they come from the workflows bundle. Fix the offending source files and re-run the build.Unresolved built-in steps — temporarily rename
node_modules/workflowtonode_modules/workflow-bak: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):
Or: delete all
"use workflow"/"use step"directives from your files. Expect:WorkflowBuildError: "No output files generated from esbuild"hintmentions"use workflow"/"use step"directives..is()discriminator — in a scratch script:Hint renders below a blank line — verify the
hintoutput appears after a blank line, not jammed onto the title line (visual formatting check).Runtime paths unaffected — run a normal workflow at runtime (
pnpm devand trigger a workflow). Confirm noWorkflowBuildErrorshows up at runtime; this class should only appear in build output.Unit tests
pnpm --filter @workflow/errors test— 19 total (4 newWorkflowBuildErrortests)pnpm --filter @workflow/builders typecheck+ test (129 pass)📚 Friendlier errors stack
Multi-PR initiative inspired by @Schniz's stalled #706:
Ansirendering primitives + context-violation errorsSerializationErrorat serialization / stream / encryption boundariesdescribeError)throw new Error(...)sitesdescribeRunError+ public subpathWorkflowBuildError+ applications in@workflow/buildersfunctionNameleak, simplify docs framing, redirect stack to user codeEach PR is stacked on the previous one; merge in order.
🤖 Generated with Claude Code