From 5d0322536ffbd488246070bc3435fa7dab01083d Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Wed, 11 Feb 2026 21:52:48 +0000 Subject: [PATCH] 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 --- src/bun.js/hot_reloader.zig | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/bun.js/hot_reloader.zig b/src/bun.js/hot_reloader.zig index ff4e580423..5516935be6 100644 --- a/src/bun.js/hot_reloader.zig +++ b/src/bun.js/hot_reloader.zig @@ -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 {