Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
5d0322536f fix(watch): replace panic with helpful error on fd exhaustion
When the file watcher fails to initialize due to exhausted file
descriptors (ProcessFdQuotaExceeded), route through handleRootError
instead of Output.panic. This provides actionable remediation steps
(ulimit, sysctl, limits.conf) and exits cleanly instead of showing
the misleading "oh no: Bun has crashed" message.

Closes #26914

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-11 21:52:48 +00:00

View File

@@ -87,12 +87,10 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime
clear_screen = clear_screen_flag;
const watcher = Watcher.init(Reloader, reloader, fs, bun.default_allocator) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.panic("Failed to enable File Watcher: {s}", .{@errorName(err)});
bun.crash_handler.handleRootError(err, @errorReturnTrace());
};
watcher.start() catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.panic("Failed to start File Watcher: {s}", .{@errorName(err)});
bun.crash_handler.handleRootError(err, @errorReturnTrace());
};
return watcher;
}
@@ -259,8 +257,7 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime
this.transpiler.fs,
bun.default_allocator,
) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.panic("Failed to enable File Watcher: {s}", .{@errorName(err)});
bun.crash_handler.handleRootError(err, @errorReturnTrace());
} }
else
.{ .hot = Watcher.init(
@@ -269,8 +266,7 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime
this.transpiler.fs,
bun.default_allocator,
) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.panic("Failed to enable File Watcher: {s}", .{@errorName(err)});
bun.crash_handler.handleRootError(err, @errorReturnTrace());
} };
if (reload_immediately) {
@@ -285,15 +281,16 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime
this.transpiler.fs,
bun.default_allocator,
) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
Output.panic("Failed to enable File Watcher: {s}", .{@errorName(err)});
bun.crash_handler.handleRootError(err, @errorReturnTrace());
};
this.transpiler.resolver.watcher = bun.resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.?);
}
clear_screen = !this.transpiler.env.hasSetNoClearTerminalOnReload(!Output.enable_ansi_colors_stdout);
reloader.getContext().start() catch @panic("Failed to start File Watcher");
reloader.getContext().start() catch |err| {
bun.crash_handler.handleRootError(err, @errorReturnTrace());
};
}
fn putTombstone(this: *@This(), key: []const u8, value: *bun.fs.FileSystem.RealFS.EntriesOption) void {