## Summary
This PR improves snapshot error messages when running tests in CI
environments to make debugging easier by showing exactly what snapshot
was being created and what value was attempted.
## Changes
### 1. Inline Snapshot Errors
**Before:**
```
Updating inline snapshots is disabled in CI environments unless --update-snapshots is used.
```
**After:**
```
Inline snapshot creation is not allowed in CI environments unless --update-snapshots is used.
If this is not a CI environment, set the environment variable CI=false to force allow.
Received: this is new
```
- Changed message to say "creation" instead of "updating" (more
accurate)
- Shows the received value that was attempted using Jest's pretty
printer
### 2. Snapshot File Errors
**Before:**
```
Snapshot creation is not allowed in CI environments unless --update-snapshots is used
If this is not a CI environment, set the environment variable CI=false to force allow.
Received: this is new
```
**After:**
```
Snapshot creation is not allowed in CI environments unless --update-snapshots is used
If this is not a CI environment, set the environment variable CI=false to force allow.
Snapshot name: "new snapshot 1"
Received: this is new
```
- Now shows the snapshot name that was being looked for
- Shows the received value using Jest's pretty printer
## Implementation Details
- Added `last_error_snapshot_name` field to `Snapshots` struct to pass
snapshot name from `getOrPut()` to error handler
- Removed unreachable code path for inline snapshot updates (mismatches
error earlier with diff)
- Updated test expectations in `ci-restrictions.test.ts`
## Test Plan
```bash
# Test inline snapshot creation in CI
cd /tmp/snapshot-test
echo 'import { test, expect } from "bun:test";
test("new inline snapshot", () => {
expect("this is new").toMatchInlineSnapshot();
});' > test.js
GITHUB_ACTIONS=1 bun test test.js
# Test snapshot file creation in CI
echo 'import { test, expect } from "bun:test";
test("new snapshot", () => {
expect("this is new").toMatchSnapshot();
});' > test2.js
GITHUB_ACTIONS=1 bun test test2.js
```
Both should show improved error messages with the received values and
snapshot name.
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
Should fix https://github.com/oven-sh/bun/issues/24104
### What does this PR do?
This PR is changing `ERR_BODY_ALREADY_USED` to be TypeError instead of
Error.
### How did you verify your code works?
A test case added to verify that request call correctly throws a
TypeError after another request call on the same Request, confirming the
fix addresses the issue.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Previously, `JSC__JSPromise__wrap` would call
`JSC::JSPromise::resolvedPromise(globalObject, result)` without checking
if an exception was thrown during promise resolution. This
could happen in certain edge cases, such as when the result value is a
thenable that triggers stack overflow, or when the promise resolution
mechanism itself encounters an error.
When such exceptions occurred, they would escape back to the Zig code,
causing the CatchScope assertion to fail with "ASSERTION FAILED:
Unexpected exception observed on thread"
instead of being properly handled.
This PR adds an exception check immediately after calling
`JSC::JSPromise::resolvedPromise()` and before the `RELEASE_AND_RETURN`
macro. If an exception is detected, the function
now clears it and returns a rejected promise with the exception value,
ensuring consistent error handling behavior. This matches the pattern
already used earlier in the function
for the initial function call exception handling.
### How did you verify your code works?
new and existing tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Fixes#20689
Previously, `@layer` blocks were not being processed through the CSS
minifier, which meant that `color-scheme` properties inside `@layer`
blocks would not get the required `--buncss-light`/`--buncss-dark`
variable injections needed for browsers that don't support the
`light-dark()` function.
## Changes
- Implemented proper minification for `LayerBlockRule` in
`src/css/rules/rules.zig:218-221`
- Added recursive call to `minify()` on nested rules, matching the
behavior of other at-rules like `@media` and `@supports`
- Added comprehensive tests for `color-scheme` inside `@layer` blocks
## Test Plan
Added three new test cases in `test/js/bun/css/css.test.ts`:
1. Simple `@layer` with `color-scheme: dark`
2. Named layers (`@layer shm.colors`) with multiple rules
3. Anonymous `@layer` with `color-scheme: light dark` (generates media
query)
All tests pass:
```bash
bun bd test test/js/bun/css/css.test.ts -t "color-scheme"
```
## Before
```css
/* Input */
@layer shm.colors {
body.theme-dark {
color-scheme: dark;
}
}
/* Output (broken - no variables) */
@layer shm.colors {
body.theme-dark {
color-scheme: dark;
}
}
```
## After
```css
/* Input */
@layer shm.colors {
body.theme-dark {
color-scheme: dark;
}
}
/* Output (fixed - variables injected) */
@layer shm.colors {
body.theme-dark {
--buncss-light: ;
--buncss-dark: initial;
color-scheme: dark;
}
}
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Implements `onTestFinished()` for `bun:test`, which runs after all
`afterEach` hooks have completed.
## Implementation
- Added `onTestFinished` export to the test module in `jest.zig`
- Modified `genericHook` in `bun_test.zig` to handle `onTestFinished` as
a special case that:
- Can only be called inside a test (not in describe blocks or preload)
- Appends hooks at the very end of the execution sequence
- Added comprehensive tests covering basic ordering, multiple callbacks,
async callbacks, and interaction with other hooks
## Execution Order
When called inside a test:
1. Test body executes
2. `afterAll` hooks (if added inside the test)
3. `afterEach` hooks
4. `onTestFinished` hooks ✨
## Test Plan
- ✅ All new tests pass with `bun bd test`
- ✅ Tests correctly fail with `USE_SYSTEM_BUN=1` (feature not in
released version)
- ✅ Verifies correct ordering with `afterEach`, `afterAll`, and multiple
`onTestFinished` calls
- ✅ Tests async `onTestFinished` callbacks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: pfg <pfg@pfg.pw>
### What does this PR do?
When `process.nextTick` is overwritten, segv will be occured via
internal `processTick` call.
This patch fixes it.
### How did you verify your code works?
Tests.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Adds missing null checking for `Bun.CookieMap#delete`.
### How did you verify your code works?
Tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
fixes: oven-sh/bun#23717
### What does this PR do?
- Align ProxyTunnel.onClose with
[HTTPClient.onClose](https://github.com/oven-sh/bun/blob/bun-v1.3.0/src/http.zig#L223-L241):
when a tunneled HTTPS response is in-progress and either
- parsing chunked trailers (trailer-line states), or
- transfer-encoding is identity with content_length == null while in
.body,
treat EOF as end-of-message and complete the request, rather than
ECONNRESET.
- Schedule proxy deref instead of deref inside callbacks to avoid
lifetime hazards.
### How did you verify your code works?
- `test/js/bun/http/proxy.test.ts`: raw TLS origin returns
close-delimited 200 OK; verified no ECONNRESET and body delivered.
- Test suite passes under bun bd test.
## Risk/compat
- Only affects CONNECT/TLS path. Direct HTTP/HTTPS unchanged. Behavior
mirrors existing
[HTTPClient.onClose](https://github.com/oven-sh/bun/blob/bun-v1.3.0/src/http.zig#L223-L241).
## Repro (minimal)
See issue; core condition is no Content-Length and no Transfer-Encoding
(close-delimited).
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
### What does this PR do?
Adds missing exception check for ReadableStream.
### How did you verify your code works?
Tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Adds support for `publicHoistPattern` in `bunfig.toml` and
`public-hoist-pattern` from `.npmrc`. This setting allows you to select
transitive packages to hoist to the root node_modules making them
available for all workspace packages.
```toml
[install]
# can be a string
publicHoistPattern = "@types*"
# or an array
publicHoistPattern = [ "@types*", "*eslint*" ]
```
`publicHoistPattern` only affects the isolated linker.
---
Adds `hoistPattern`. `hoistPattern` is the same as `publicHoistPattern`,
but applies to the `node_modules/.bun/node_modules` directory instead of
the root node_modules. Also the default value of `hoistPattern` is `*`
(everything is hoisted to `node_modules/.bun/node_modules` by default).
---
Fixes a determinism issue constructing the
`node_modules/.bun/node_modules` directory.
---
closes#23481closes#6160closes#23548
### How did you verify your code works?
Added tests for
- [x] only include patterns
- [x] only exclude patterns
- [x] mix of include and exclude
- [x] errors for unexpected expression types
- [x] excluding direct dependency (should still include)
- [x] match all with `*`
- [x] string and array expression types
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
`short` is signed in C++ by default and not unsigned. Switched to
`uint16_t` so it's unambiguous.
### How did you verify your code works?
There is a test
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Fixed an off-by-one error in buffer allocation for several path module
functions when handling paths longer than `PATH_SIZE` (typically 4096
bytes on most platforms).
## Changes
- `normalizeJS_T`: Added +1 to buffer allocation for null terminator
- `relativeJS_T`: Added +1 to buffer allocation for null terminator
- `toNamespacedPathJS_T`: Added +9 bytes (8 for possible UNC prefix + 1
for null terminator)
## Test plan
- Added tests for `path.normalize()` with paths up to 100,000 characters
- Added tests for `path.relative()` with very long paths
- All existing path tests continue to pass
The issue occurred because when a path is exactly equal to or longer
than `PATH_SIZE`, the buffer was allocated with size equal to the path
length, but then a null terminator was written at `buf[bufSize]`, which
was out of bounds.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
Fixes a panic that occurred when a WebSocket close frame's payload was
split across multiple TCP packets.
## The Bug
The panic occurred at `websocket_client.zig:681`:
```
panic: index out of bounds: index 24, len 14
```
This happened when:
- A close frame had a payload of 24 bytes (2 byte code + 22 byte reason)
- The first TCP packet contained 14 bytes (header + partial payload)
- The code tried to access `data[2..24]` causing the panic
## Root Causes
1. **Bounds checking issue**: The code assumed all close frame data
would arrive in one packet and tried to `@memcpy` without verifying
sufficient data was available.
2. **Premature flag setting**: `close_received = true` was set
immediately upon entering the close state. This prevented `handleData`
from being called again when the remaining bytes arrived (early return
at line 354).
## The Fix
Implemented proper fragmentation handling for close frames, following
the same pattern used for ping frames:
- Added `close_frame_buffering` flag to track buffering state
- Buffer incoming data incrementally using the existing
`ping_frame_bytes` buffer
- Track total expected length and bytes received so far
- Only set `close_received = true` after all bytes are received
- Wait for more data if the frame is incomplete
## Testing
- Created two regression tests that fragment close frames across
multiple packets
- All existing WebSocket tests pass (`test/js/web/websocket/`)
- Verified the original panic no longer occurs
## Related
This appears to be the root cause of crashes reported on Windows when
WebSocket connections close, particularly when close frames have reasons
that get fragmented by the network stack.
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
### What does this PR do?
Let MySQL unref when idle and make sure that is behaving like this.
Only set up the timers after all status changes are complete since the
timers rely on the status to determine timeouts, this was causing the
CPU usage spike to 100% (thats why only happened in TLS)
CPU usage it self will be improved in
https://github.com/oven-sh/bun/pull/23700 not in this PR
Fixes: https://github.com/oven-sh/bun/issues/23273
Fixes: https://github.com/oven-sh/bun/issues/23256
### How did you verify your code works?
Test
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
### What does this PR do?
Fixes#23489
The YAML parser was incorrectly treating `...` inside double-quoted
strings as document end markers, causing parse errors for strings
containing ellipsis, particularly affecting internationalized text.
### Example of the bug:
```yaml
balance: "👛 لا تمتلك محفظة... !"
```
This would fail with: `error: Unexpected document end`
### Root cause:
The bug was introduced in commit fcbd57ac48 which attempted to optimize
document marker detection by using `self.line_indent == .none` instead
of tracking newlines with a local flag. However, this check was
incomplete - it didn't track whether we had just processed a newline
character.
### The fix:
Restored the `nl` (newline) flag pattern from the single-quoted scanner
and combined it with the `line_indent` check. Document markers `...` and
`---` are now only recognized when **all** of these conditions are met:
1. We're after a newline (`nl == true`)
2. We're at column 0 (`self.line_indent == .none`)
3. Followed by whitespace or EOF
This allows `...` to appear freely in double-quoted strings while still
correctly recognizing actual document end markers at the start of lines.
### How did you verify your code works?
1. Reproduced the original issue from #23489
2. Applied the fix and verified all test cases pass:
- Original Arabic text with emoji: `"👛 لا تمتلك محفظة... !"`
- Various `...` positions: start, middle, end
- Both single and double quotes
- Multiline strings with indented `...` (issue #22392)
3. Created regression test in `test/regression/issue/23489.test.ts`
4. Verified existing YAML tests still pass (514 pass, up from 513)
cc @dylan-conway for review
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
## Summary
Fixes a panic that occurred when passing `NumberObject` or
`BooleanObject` as MySQL query parameters.
**Panic message:** `A JavaScript exception was thrown, but it was
cleared before it could be read.`
## Root Cause
The `FieldType.fromJS` function in `src/sql/mysql/MySQLTypes.zig` was
returning `error.JSError` without throwing a JavaScript exception first
for:
- `NumberObject` (created via `new Number(42)`)
- `BooleanObject` (created via `new Boolean(true)`)
- Non-indexable types
This violated the contract that `error.JSError` means "an exception has
already been thrown and is ready to be taken."
## Call Chain
1. User executes `await sql\`SELECT ${new Number(42)} as value\``
2. `FieldType.fromJS()` detects `.NumberObject` and returns
`error.JSError` without throwing
3. Error propagates to `MySQLQuery.runPreparedQuery()`
4. Code checks `hasException()` → returns false (no exception exists!)
5. Calls `mysqlErrorToJS(globalObject, "...", error.JSError)`
6. `mysqlErrorToJS` tries to `takeException(error.JSError)` but there's
no exception
7. **PANIC**
## Fix
The fix throws a proper exception with a helpful message before
returning `error.JSError`:
- `"Cannot bind NumberObject to query parameter. Use a primitive number
instead."`
- `"Cannot bind BooleanObject to query parameter. Use a primitive
boolean instead."`
- `"Cannot bind this type to query parameter"`
## Test Plan
Added regression tests in `test/js/sql/sql-mysql.test.ts`:
- Test passing `NumberObject` as parameter
- Test passing `BooleanObject` as parameter
Both tests verify that a proper error is thrown instead of crashing.
Verified manually with local MySQL server that:
- ✅ NumberObject now throws proper error (was crashing)
- ✅ BooleanObject now throws proper error (was crashing)
- ✅ Primitive numbers still work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Adds a new `--only-failures` flag to `bun test` that only displays test
failures, similar to `--dots` but without printing dots for each test.
## Motivation
When running large test suites or in CI environments, users often only
care about test failures. The existing `--dots` reporter reduces
verbosity by showing dots, but still requires visual scanning to find
failures. The `--only-failures` flag provides a cleaner output by
completely suppressing passing tests.
## Changes
- Added `--only-failures` CLI flag in `Arguments.zig`
- Added `only_failures` boolean to the test reporters struct in
`cli.zig`
- Updated test output logic in `test_command.zig` to skip non-failures
when flag is set
- Updated `jest.zig` and `bun_test.zig` to handle the new flag
- Added comprehensive tests in `only-failures.test.ts`
## Usage
```bash
bun test --only-failures
```
Example output (only shows failures):
```
test/example.test.ts:
(fail) failing test
error: expect(received).toBe(expected)
Expected: 3
Received: 2
5 pass
1 skip
2 fail
Ran 8 tests across 1 file.
```
## Test Plan
- Verified `--only-failures` flag only shows failing tests
- Verified normal test output still works without the flag
- Verified `--dots` reporter still works correctly
- Added regression tests with snapshot comparisons
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
## Summary
Fixes two critical bugs in Bun Shell:
1. **Memory leaks & incorrect GC reporting**: Shell objects weren't
reporting their memory usage to JavaScriptCore's garbage collector,
causing memory to accumulate unchecked. Also fixes a leak where
`ShellArgs` wasn't being freed in `Interpreter.finalize()`.
2. **Blocking I/O on macOS**: Fixes a bug where writing large amounts of
data (>1MB) to pipes would block the main thread on macOS. The issue:
`sendto()` with `MSG_NOWAIT` flag blocks on macOS despite the flag, so
we now avoid the socket fast path unless the socket is already
non-blocking.
## Changes
- Adds `memoryCost()` and `estimatedSize()` implementations across shell
AST nodes, interpreter, and I/O structures
- Reports estimated memory size to JavaScriptCore GC via
`vm.heap.reportExtraMemoryAllocated()`
- Fixes missing `this.args.deinit()` call in interpreter finalization
- Fixes `BabyList.memoryCost()` to return bytes, not element count
- Conditionally uses socket fast path in IOWriter based on platform and
socket state
## Test plan
- [x] New test: `shell-leak-args.test.ts` - validates memory doesn't
leak during parsing/execution
- [x] New test: `shell-blocking-pipe.test.ts` - validates large pipe
writes don't block the main thread
- [x] Existing shell tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
## Summary
Fixes a panic that occurred when formatting deeply nested objects with
many properties in test output.
## Problem
The `writeIndent()` function in `pretty_format.zig:648` performed
`written * 2` which triggered integer overflow checking in debug builds
when formatting complex nested structures.
**Original crash:**
```
panic: integer overflow
writeIndent at bun.js/test/pretty_format.zig:648
```
**Platform:** Windows x86_64_baseline, Bun v1.3.0
## Solution
Changed from:
```zig
try writer.writeAll(buf[0 .. written * 2]);
```
To:
```zig
const byte_count = @min(buf.len, written *% 2);
try writer.writeAll(buf[0..byte_count]);
```
- Used wrapping multiplication (`*%`) to prevent overflow panic
- Added bounds checking with `@min(buf.len, ...)` for safety
- Maintains correct behavior while preventing crashes
## Test
Added regression test at
`test/js/bun/test/pretty-format-overflow.test.ts` that:
- Creates deeply nested objects (500 levels with 50 properties each)
- Verifies no panic/overflow/crash occurs when formatting
- Uses exact configuration that triggered the original crash
## Verification
- ✅ Test passes with the fix
- ✅ Test would crash without the fix (in debug builds)
- ✅ No changes to behavior, only safety improvement
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
### What does this PR do?
### How did you verify your code works?
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixed an unsigned integer underflow in the bounds check for
`writeBigInt64LE`, `writeBigInt64BE`, `writeBigUInt64LE`, and
`writeBigUInt64BE` methods.
## Problem
When `byteLength < 8`, the bounds check `offset > byteLength - 8` would
cause unsigned integer underflow (since both are `size_t`), resulting in
a large positive number that would pass the check. This allowed
out-of-bounds writes and caused ASAN use-after-poison errors.
**Reproduction:**
```js
const buf = Buffer.from("Hello World");
const slice = buf.slice(0, 5);
slice.writeBigUInt64BE(4096n, 10000); // ASAN error!
```
## Solution
Added an explicit `byteLength < 8` check before the subtraction to
prevent the underflow. The fix is applied to all four functions:
- `writeBigInt64LE` (src/bun.js/bindings/JSBuffer.cpp:2464)
- `writeBigInt64BE` (src/bun.js/bindings/JSBuffer.cpp:2504)
- `writeBigUInt64LE` (src/bun.js/bindings/JSBuffer.cpp:2543)
- `writeBigUInt64BE` (src/bun.js/bindings/JSBuffer.cpp:2582)
## Test plan
- Added comprehensive regression tests covering all edge cases
- Verified the original reproduction case now throws a proper RangeError
instead of crashing
- All tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
Fixes an assertion failure that occurred when `URLSearchParams.toJSON()`
was called with numeric string keys.
## The Problem
When using numeric string keys (e.g., `"39208"`, `"0"`, `"100"`),
calling `toJSON()` would trigger:
```
ASSERTION FAILED: !parseIndex(propertyName)
cache/webkit-6d0f3aac0b817cc0/include/JavaScriptCore/JSObjectInlines.h:444
```
Reproduction:
```javascript
const params = new URLSearchParams();
params.set("39208", "updated");
params.toJSON(); // crashes
```
## Root Cause
The `getInternalProperties` function in `JSURLSearchParams.cpp` was
using `putDirect()` to add properties to the result object. However,
`putDirect()` cannot be used with property names that can be parsed as
array indices - JSC expects such properties to use indexed storage
instead.
## The Fix
- Replace `putDirect()` with `putDirectMayBeIndex()`, which
automatically handles both regular properties and numeric indices
- Replace `getDirect()` with `get()` to properly retrieve values for
both types of properties
## Test Plan
Added comprehensive tests to `test/js/web/html/URLSearchParams.test.ts`:
- ✅ Single numeric string keys
- ✅ Multiple numeric keys
- ✅ Mixed numeric and non-numeric keys
- ✅ Duplicate numeric keys
- ✅ Extra arguments (original crash case)
All tests pass, and the original crash no longer occurs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
Fixes a panic that occurred when `console.log()` tried to format a Set
or Map instance with a non-numeric `size` property.
## Issue
When a Set or Map subclass overrides the `size` property with a
non-numeric value (like a constructor function, string, or other
object), calling `console.log()` on the instance would trigger a panic:
```javascript
class C1 extends Set {
constructor() {
super();
Object.defineProperty(this, "size", {
writable: true,
enumerable: true,
value: Set
});
console.log(this); // panic!
}
}
new C1();
```
## Root Cause
In `src/bun.js/ConsoleObject.zig`, the Map and Set formatting code
called `toInt32()` directly on the `size` property value. This function
asserts that the value is not a Cell (objects/functions), causing a
panic when `size` was overridden with non-numeric values.
## Solution
Changed both Map and Set formatting to use `coerce(i32, globalThis)`
instead of `toInt32()`. This properly handles non-numeric values using
JavaScript's standard type coercion rules and propagates any coercion
errors appropriately.
## Test Plan
Added regression tests to `test/js/bun/util/inspect.test.js` that verify
Set and Map instances with overridden non-numeric `size` properties can
be inspected without panicking.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
### What does this PR do?
reduce memory usage when streaming (this should be a temporary solution
until owned_and_done is fixed)
### How did you verify your code works?
Added a test that should not be flaky in CI
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Fixes unhelpful FFI error messages that made debugging extremely
difficult. The user reported that when dlopen fails, the error doesn't
tell you which library failed or why.
**Before:**
```
Failed to open library. This is usually caused by a missing library or an invalid library path.
```
**After:**
```
Failed to open library "libnonexistent.so": /path/libnonexistent.so: cannot open shared object file: No such file or directory
```
### How did you verify your code works?
1. **Cross-platform compilation verified**
- Ran `bun run zig:check-all` - all platforms compile successfully
(Windows, macOS x86_64/arm64, Linux x86_64/arm64 glibc/musl)
2. **Added comprehensive regression tests**
(`test/regression/issue/dlopen-missing-symbol-error.test.ts`)
- ✅ Tests dlopen error shows library name when it can't be opened
- ✅ Tests dlopen error shows symbol name when symbol isn't found
- ✅ Tests linkSymbols shows helpful error when ptr is missing
- ✅ Tests handle both glibc and musl libc systems
3. **Manually tested error messages**
- Missing library: Shows full path and "No such file or directory"
- Invalid library: Shows "invalid ELF header"
- Missing symbol: Shows symbol and library name
- linkSymbols without ptr: Shows helpful explanation
### Implementation Details
1. **Created cross-platform getDlError() helper**
(src/bun.js/api/ffi.zig:8-21)
- On POSIX: Calls `std.c.dlerror()` to get actual system error message
- On Windows: Returns generic message (detailed errors handled in C++
layer via `GetLastError()` + `FormatMessageW()`)
- Follows the pattern established in `BunProcess.cpp` for dlopen error
handling
2. **Improved error messages**
- dlopen errors now include library name and system error details
- linkSymbols errors explain the ptr field requirement clearly
- Symbol lookup errors already showed both symbol and library name
3. **Fixed linkSymbols error propagation** (src/js/bun/ffi.ts:529)
- Added missing `if (Error.isError(result)) throw result;` check
- Now consistent with dlopen which already had this check
### Example Error Messages
- **Missing library:** `Failed to open library "libnonexistent.so":
cannot open shared object file: No such file or directory`
- **Invalid library:** `Failed to open library "/etc/passwd": invalid
ELF header`
- **Missing symbol:** `Symbol "nonexistent_func" not found in
"libc.so.6"`
- **Missing ptr:** `Symbol "myFunc" is missing a "ptr" field. When using
linkSymbols() or CFunction()...`
Fixes the issue mentioned in:
https://fxtwitter.com/hassanalinali/status/1977710104334963015🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Adds comprehensive support to `generate-classes.ts` for JavaScript
classes that need both named WriteBarrier members (like callbacks) and a
dynamic array of JSValues, all properly tracked by the garbage
collector. This replaces error-prone manual `protect()/unprotect()`
calls with proper GC integration.
## Motivation
The shell interpreter was using `JSValue.protect()/unprotect()` to keep
JavaScript objects alive, which caused memory leaks when cleanup paths
didn't properly unprotect values. This is a common pattern that needed a
better solution.
## What Changed
### Code Generator (`generate-classes.ts`)
When a class has both `values: ["resolve", "reject"]` and `valuesArray:
true`:
**Generated C++ class gets:**
- `WTF::FixedVector<JSC::WriteBarrier<JSC::Unknown>> jsvalueArray`
member for dynamic array
- Individual `JSC::WriteBarrier<JSC::Unknown> m_resolve, m_reject`
members for named values
- 4 `create()` overloads covering all combinations:
1. Basic: `create(vm, globalObject, structure, ptr)`
2. Array only: `create(..., FixedVector<WriteBarrier<Unknown>>&&)`
3. Named values: `create(..., JSValue resolve, JSValue reject)`
4. Both: `create(..., FixedVector&&, JSValue resolve, JSValue reject)`
**Constructor overloads using `WriteBarrierEarlyInit`:**
```cpp
JSShellInterpreter(VM& vm, Structure* structure, void* ptr,
JSValue resolve, JSValue reject)
: Base(vm, structure)
, m_resolve(resolve, JSC::WriteBarrierEarlyInit) // ← Key technique
, m_reject(reject, JSC::WriteBarrierEarlyInit)
{
m_ctx = ptr;
}
```
The `WriteBarrierEarlyInit` tag allows initializing WriteBarriers in the
constructor initializer list before the object is fully constructed,
which is required for proper GC integration.
**Extern C bridge functions:**
- `TypeName__createWithValues(globalObject, ptr, markedArgumentBuffer*)`
- `TypeName__createWithInitialValues(globalObject, ptr, resolve,
reject)`
- `TypeName__createWithValuesAndInitialValues(globalObject, ptr,
buffer*, resolve, reject)`
**Zig convenience wrappers:**
- `toJSWithValues(this, globalObject, markedArgumentBuffer)`
- `toJSWithInitialValues(this, globalObject, resolve, reject)`
- `toJSWithValuesAndInitialValues(this, globalObject, buffer, resolve,
reject)`
### Shell Interpreter Memory Leak Fix
**Before:**
```zig
const js_value = JSShellInterpreter.toJS(interpreter, globalThis);
resolve.protect(); // Manual reference counting
reject.protect();
// ... later in cleanup ...
resolve.unprotect(); // Easy to forget/miss in error paths
reject.unprotect();
```
**After:**
```zig
const js_value = Bun__createShellInterpreter(
globalThis,
interpreter,
parsed_shell_script,
resolve, // Stored with WriteBarrierEarlyInit
reject, // GC tracks automatically
);
// No manual memory management needed!
```
### Supporting Changes
- Added `MarkedArgumentBuffer.wrap()` helper in Zig for safe
MarkedArgumentBuffer usage
- Created `ShellBindings.cpp` with `Bun__createShellInterpreter()` using
the new API
- Removed all `protect()/unprotect()` calls from shell interpreter
- Applied pattern to both `ShellInterpreter` and `ShellArgs` classes
## Benefits
1. **No memory leaks**: GC tracks all references automatically
2. **Safer**: Cannot forget to unprotect values
3. **Cleaner code**: No manual reference counting
4. **Reusable**: Pattern works for any class needing to store JSValues
5. **Performance**: Same cost as manual protect/unprotect but safer
## Testing
Existing shell tests verify the functionality. The pattern is already
used throughout JavaScriptCore for similar cases (see
`JSWrappingFunction`, `AsyncContextFrame`, `JSModuleMock`, etc.)
## When to Use This Pattern
Use `values` + `valuesArray` + `WriteBarrierEarlyInit` when:
- Your C++ class needs to keep JavaScript values alive
- You have both known named callbacks AND dynamic arrays of values
- You want the GC to track references instead of manual
protect/unprotect
- Your class extends `JSDestructibleObject`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Makes sure strings are doubled quoted when they start with flow
indicators and `:`.
Fixes#23502
### How did you verify your code works?
Added tests for each indicator in flow and block context
### What does this PR do?
Fixes `bun -p "process.stderr.write('Hello' +
String.fromCharCode(0xd800))"`.
Also fixes potential index out of bounds if there are many invalid
sequences.
This also affects `TextEncoder`.
### How did you verify your code works?
Added tests for edgecases
---------
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
### What does this PR do?
Calls `uncork()` after flushing response headers to ensure data is sent
as soon as possible, improving responsiveness.
This behavior still works correctly even without the explicit `uncork()`
call, due to the deferred uncork logic implemented here:
6e3359dd16/packages/bun-uws/src/Loop.h (L57-L64)
A test already covers this scenario in
`test/js/node/test/parallel/test-http-flush-response-headers.js`.
### How did you verify your code works?
CI
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
fix tests failing because of example.com
### How did you verify your code works?
CI
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Fixes#23333, Fixes#13978
### What does this PR do?
### How did you verify your code works?
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
Co-authored-by: Zack Radisic <zack@theradisic.com>
## What does this PR do?
Bumps Bun version from 1.2.24 to 1.3.0, marking the start of the 1.3.x
release series.
## Changes
- **`package.json`**: Updated version from `1.2.24` to `1.3.0`
- **`LATEST`**: Updated from `1.2.23` to `1.3.0` (used by installation
scripts)
- **`test/bundler/bundler_bun.test.ts`**: Updated version check to
include `1.3.x` so export conditions tests continue to run
## Verification
✅ Debug build successful showing version `1.3.0-debug`
✅ All platforms compile successfully via `bun run zig:check-all` (49/49
steps)
✅ Bundler tests pass with updated version check
## Additional Notes
- CI workflow Bun versions (e.g., `1.2.3`, `1.2.0` in
`.github/workflows/release.yml`) are intentionally left unchanged -
these are pinned versions used to run the release tooling, not the
version being released
- Docker images use `ARG BUN_VERSION` passed at build time and don't
need updates
- The actual release version comes from git tags via `${{
env.BUN_VERSION }}`
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Fixes#23380 - this is a use-case for the `--only` flag that I missed
Adds back the `--only` flag. When running `bun test` on a full test
suite, without this flag it will run only that test in its file, but it
will run all other tests from other files. With this flag, it will not
run things from other files.
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>