Skip to content

Conversation

robobun
Copy link
Collaborator

@robobun robobun commented Oct 12, 2025

What does this PR do?

When running under AI agent mode (detected via Output.isAIAgent()), this PR changes error message formatting to consistently use error: as the prefix instead of the specific error type (TypeError, ReferenceError, etc.). The actual error type is then shown as a name property below the error message.

This allows AI agents to reliably search for all errors using a simple pattern:

command 2>&1 | grep "^error:"

instead of needing to match multiple patterns like:

grep -E "^(Error|TypeError|ReferenceError|SyntaxError|RangeError|...):"

Before (AI agent mode):

TypeError: This is a test error
      at /tmp/test.js:2:11

After (AI agent mode):

error: This is a test error
 name: "TypeError"

      at /tmp/test.js:2:11

How did you verify your code works?

  1. Built Bun with the changes: bun bd
  2. Tested with various error types (TypeError, ReferenceError, SyntaxError, RangeError) to confirm they all show error: prefix in AI agent mode
  3. Verified that generic Error instances don't show the name property (since it's redundant)
  4. Tested the grep pattern to confirm it reliably catches all errors:
    $ ./build/debug/bun-debug test-various-errors.js 2>&1 | grep "^error:"
    error: undefined variable
    error: invalid syntax
    error: out of range
  5. Confirmed that normal mode (non-AI agent) behavior remains unchanged

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

When Output.isAIAgent() returns true (i.e., when running under Claude Code
or similar AI tools), error messages now consistently use "error:" as the
prefix instead of the specific error type (TypeError, ReferenceError, etc.).
The actual error type is shown as a property below the error message.

This allows AI agents to reliably search for errors using a simple pattern:
  command 2>&1 | grep "^error:"
instead of needing to match multiple patterns like:
  grep -E "^(Error|TypeError|ReferenceError|SyntaxError|RangeError|...):"

Before (AI agent mode):
  TypeError: This is a test error

After (AI agent mode):
  error: This is a test error
   name: "TypeError"

This provides a more consistent and parseable format for AI tools while
still preserving all error information.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@robobun
Copy link
Collaborator Author

robobun commented Oct 12, 2025

Updated 9:26 AM PT - Oct 12th, 2025

❌ Your commit e7ff151c has 2 failures in Build #28962 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 23532

That installs a local version of the PR into your bun-23532 executable, so you can run:

bun-23532 --bun

Copy link
Contributor

coderabbitai bot commented Oct 12, 2025

Walkthrough

Add AI-agent-specific branches to error printing: suppress ANSI coloring, adjust longest-property padding cap, print an explicit name property first when present/not "Error", short-circuit name/message formatting in AI mode, then print remaining properties with adjusted padding.

Changes

Cohort / File(s) Summary of changes
AI agent error printing adjustments
src/bun.js/VirtualMachine.zig
Add branching when Output.isAIAgent() to avoid ANSI colors; increase longest property padding cap to 10 in AI mode; when an error has a name field not equal to "Error", print that name first and mark the first-property to avoid duplicate printing; short-circuit printErrorNameAndMessage in AI mode to return an empty display_name with the message; continue iterating and printing other properties with adjusted padding.

Possibly related PRs

Suggested reviewers

  • pfgithub
  • dylan-conway

Pre-merge checks

✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately highlights the primary change—using an "error:" prefix alongside a name property in AI agent mode—without extraneous details or noise.
Description Check ✅ Passed The pull request description follows the repository template by including both the "What does this PR do?" and "How did you verify your code works?" sections, clearly describing the behavior change and providing detailed verification steps.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between eeb8ae5 and e7ff151.

📒 Files selected for processing (1)
  • src/bun.js/VirtualMachine.zig (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/bun.js/VirtualMachine.zig
src/bun.js/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)

src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy

Files:

  • src/bun.js/VirtualMachine.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/bun.js/VirtualMachine.zig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Format
🔇 Additional comments (4)
src/bun.js/VirtualMachine.zig (4)

1961-1962: LGTM! ANSI color handling for AI agent mode.

The logic correctly disables ANSI colors when in AI agent mode to ensure grep '^error:' works reliably without escape codes interfering with start-of-line matching.


2001-2003: LGTM! Consistent ANSI handling across error handlers.

Correctly disables ANSI colors in AI agent mode, consistent with the change in printException. The duplication is necessary since runErrorHandler is a separate entry point.


3118-3141: LGTM! Well-implemented name property handling for AI agent mode.

The implementation correctly:

  • Includes the "name" property length when calculating padding for alignment
  • Prints the name property first (after the error message) when in AI agent mode
  • Skips the name property for generic "Error" instances as documented in the PR
  • Uses saturating subtraction to safely handle padding calculation

The example output in the comment clearly demonstrates the expected format.


3311-3323: LGTM! Correct implementation of normalized error prefix for AI agent mode.

  • Suppresses the "frontend " prefix in AI agent mode to ensure errors start at column 0
  • Returns an empty display_name in AI agent mode, producing the consistent "error:" prefix
  • Documentation clearly explains the grepability benefit

Verify that error_display_level.formatter(String.empty, …) with .include_colon produces "error:" as expected across all error display levels.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 40da082 and 4a19e58.

📒 Files selected for processing (1)
  • src/bun.js/VirtualMachine.zig (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/bun.js/VirtualMachine.zig
src/bun.js/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)

src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy

Files:

  • src/bun.js/VirtualMachine.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/bun.js/VirtualMachine.zig
🔇 Additional comments (2)
src/bun.js/VirtualMachine.zig (2)

3116-3124: LGTM! Clean padding calculation for AI agent mode.

The logic correctly ensures consistent padding across all properties, including the manually printed name property. The bounding to 10 is reasonable to prevent excessive indentation while maintaining readability.


3127-3139: LGTM! Proper coordination with iterator loop.

The manual printing of the name property is well-implemented. The is_first_property flag correctly prevents duplicate printing since the iterator loop skips name at line 3142. The padding and formatting are consistent with other properties.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4a19e58 and eeb8ae5.

📒 Files selected for processing (1)
  • src/bun.js/VirtualMachine.zig (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/bun.js/VirtualMachine.zig
src/bun.js/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)

src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy

Files:

  • src/bun.js/VirtualMachine.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/bun.js/VirtualMachine.zig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Format
🔇 Additional comments (1)
src/bun.js/VirtualMachine.zig (1)

3116-3125: Solid AI-agent property handling; prints name first and aligns padding.

  • Including "name" in longest-name calc and printing it first avoids duplication and preserves grepable header.
  • Padding via saturating subtraction is safe.

Also applies to: 3127-3139

This ensures that grep '^error:' works reliably in all scenarios:
- ANSI escape codes are disabled to prevent them from appearing before 'error:'
- The 'frontend' prefix is suppressed so browser errors also start with 'error:'

These changes guarantee that the error prefix is always at column 0 for
easy grepping by AI agents.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant