Skip to content

Fix function build errors not rendering actual failure reason#7216

Closed
davejcameron wants to merge 1 commit into
mainfrom
dc.fix-function-build-error-rendering
Closed

Fix function build errors not rendering actual failure reason#7216
davejcameron wants to merge 1 commit into
mainfrom
dc.fix-function-build-error-rendering

Conversation

@davejcameron

Copy link
Copy Markdown
Contributor

Summary

  • When a Shopify Function build command fails (e.g. cargo/rust not installed), app-event-watcher only wrote error.message ("Failed to build function.") to stderr, completely hiding the actual failure reason
  • The detail was stored in error.tryMessage (e.g. "Command failed with exit code 127: cargo build --release") but never rendered
  • Now writes tryMessage to stderr when present, so users see why their build actually failed

Test plan

  • Added test in app-event-watcher.test.ts verifying tryMessage content is written to stderr
  • Added tests in extension.test.ts verifying tryMessage is preserved when wrapping ExternalError and generic errors
  • All existing tests pass
  • Lint and typecheck pass

🤖 Generated with Claude Code

When a Shopify Function build fails (e.g. cargo/rust not installed),
the app-event-watcher only wrote error.message ("Failed to build
function.") to stderr, ignoring error.tryMessage which contains the
actual failure details. Now also writes tryMessage when present.
@davejcameron davejcameron marked this pull request as ready for review April 7, 2026 17:04
@davejcameron davejcameron requested a review from a team as a code owner April 7, 2026 17:04
Copilot AI review requested due to automatic review settings April 7, 2026 17:04

Copilot AI 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

Improves the developer experience when Shopify Function builds fail during dev by ensuring the underlying failure reason (stored in tryMessage) is written to stderr instead of only showing a generic error message.

Changes:

  • Print error.tryMessage to stderr in AppEventWatcher when present, to surface the actual build failure reason.
  • Add a dev watcher test to verify tryMessage content is included in stderr output.
  • Add build service tests to verify build command failure details are preserved in AbortError.tryMessage.

Reviewed changes

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

File Description
packages/app/src/cli/services/dev/app-events/app-event-watcher.ts Writes tryMessage to stderr on non-esbuild build errors.
packages/app/src/cli/services/dev/app-events/app-event-watcher.test.ts Adds coverage asserting tryMessage details appear in stderr output.
packages/app/src/cli/services/build/extension.test.ts Adds coverage asserting build command failures propagate details via tryMessage.

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

Comment on lines +292 to +294
this.options.stderr.write(
typeof error.tryMessage === 'string' ? error.tryMessage : String(error.tryMessage),
)

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

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

When printing error.message and then error.tryMessage, the two writes are concatenated with no separator, so users may see a single glued string (e.g., Failed to build function.Command failed ...). Consider writing a newline (or \n\n) between them, or only adding a separator if error.message doesn’t already end with one, so the output is readable.

Suggested change
this.options.stderr.write(
typeof error.tryMessage === 'string' ? error.tryMessage : String(error.tryMessage),
)
const tryMessage =
typeof error.tryMessage === 'string' ? error.tryMessage : String(error.tryMessage)
if (!String(error.message).endsWith('\n')) {
this.options.stderr.write('\n')
}
this.options.stderr.write(tryMessage)

Copilot uses AI. Check for mistakes.
Comment on lines +291 to +295
if (error.tryMessage) {
this.options.stderr.write(
typeof error.tryMessage === 'string' ? error.tryMessage : String(error.tryMessage),
)
}

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

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

AbortError.tryMessage is typed as a TokenItem | null (not necessarily a plain string). Using String(error.tryMessage) can yield [object Object] for tokenized messages. Since this file already imports from @shopify/cli-kit/node/output, consider using itemToString(error.tryMessage) (or equivalent) to reliably render token items to a human-readable string before writing to stderr.

Copilot uses AI. Check for mistakes.
@github-actions

Copy link
Copy Markdown
Contributor

This PR seems inactive. If it's still relevant, please add a comment saying so. Otherwise, take no action.
→ If there's no activity within a week, then a bot will automatically close this.
Thanks for helping to improve Shopify's dev tooling and experience.

Copy link
Copy Markdown
Contributor

Copilot messages make sense, let's fix those and we can merge this!

@github-actions

Copy link
Copy Markdown
Contributor

This PR seems inactive. If it's still relevant, please add a comment saying so. Otherwise, take no action.
→ If there's no activity within a week, then a bot will automatically close this.
Thanks for helping to improve Shopify's dev tooling and experience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants