AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

False Positive 'UsePathname() Outside Of <Suspense>' During Bun Build Due To Unhandled Rejection In Aborted Render Signal

When building with bun --bun, Next.js logs a spurious error about usePathname outside Suspense for routes with fallback params, even though the component is inside Suspense. Root cause is an unhandled promise rejection in the aborted branch of makeHangingPromiseWithError, which Bun does not filter because AsyncLocalStorage context is missing in unhandledRejection listeners.

mediumConfidence 95%Next.jsAffected V16.3.7Affected V16.4.0-Canary.57

Origin Analysis

During client prerender, after the render signal is aborted, React re-invokes the component to build the component stack for error reporting. In makeHangingPromiseWithError, the signal.aborted branch returns Promise.reject(error) without attaching a catch handler. Node's unhandledRejection filter uses workUnitAsyncStorage.getStore() to detect aborted render signals and suppresses the rejection, but Bun does not run unhandledRejection listeners within the promise's async context, causing getStore() to return undefined and the rejection to be logged as an error.
1. Clone repro: https://github.com/bigfree/next-bun-unhandled-rejection-repro 2. Run bun install 3. Run bun run build:bun 4. Observe spurious error for /items/[id] despite Suspense boundary 5. Compare with bun run build:node which is clean

Fixing Code Block

// 修改文件: node_modules/next/dist/server/lib/render-server.js (或实际对应源码位置) // 在 makeHangingPromiseWithError 函数中,将 if (signal.aborted) 分支修改为: if (signal.aborted) { const rejected = Promise.reject(error) rejected.catch(ignoreReject) return rejected }
Attaching a catch handler to the rejected promise in the aborted branch ensures the rejection is handled internally and does not propagate as unhandled, matching the behavior of the normal hanging promise path. This prevents the bogus error without affecting functionality.

Edge Case Audit

This fix only silences the unhandled rejection; it does not address the underlying Bun AsyncLocalStorage context loss, which may cause other undetected unhandled rejections during build. The change may be overwritten by Next.js updates, so reapply after upgrading. Ensure the ignoreReject function is available in scope. Rollback is safe by reverting the code to the original promise rejection without catch, though the spurious logs will reappear.

Ecosystem Topology