Skip to content

Conversation

@sokra
Copy link
Member

@sokra sokra commented Feb 9, 2026

What?

This PR improves error reporting for webpack loaders by:

  1. Preserving loader paths in error messages: Modified the webpack message formatter to rewrite "Module build failed" headers to preserve the loader path information while removing the verbose prefix. This makes errors more readable in both CLI output and error overlays.

  2. Better error wrapping for non-Error throws: When loaders throw non-Error values (strings, objects, etc.), the error is now wrapped with loader path information in the stack trace, making it easier to identify which loader caused the error.

  3. Catching deferred loader errors: Added handling for errors that occur after loader completion (e.g., unhandled Promise rejections, setTimeout throws) by:

    • Adding an unhandledRejection handler in the IPC layer
    • Delaying resolution in webpack-loaders transform to allow error handlers to fire before sending the 'end' message
  4. Comprehensive test coverage: Added e2e tests covering various error scenarios (Error throws, string throws, Promise rejections, setTimeout errors) with verification of both CLI output and error overlay display.

Why?

Webpack loader errors were previously difficult to debug because:

  • The verbose "Module build failed" prefix obscured the actual error message
  • Non-Error throws lost their context and loader information
  • Deferred errors (Promise rejections, async throws) were not properly surfaced
  • Error overlays didn't clearly show which loader caused the problem

How?

  • format-webpack-messages.ts: Changed from filtering out loader headers to rewriting them, preserving the (from ./loaders/...) information
  • webpack-loaders.ts: Added error wrapping for non-Error values and deferred resolution to catch async errors
  • ipc/index.ts: Added unhandledRejection handler to surface Promise-related errors
  • Test suite: Added comprehensive e2e tests with multiple loader error scenarios

Fixes #

https://claude.ai/code/session_01XnHv9KVqYRDLDti1q6vni4

@nextjs-bot nextjs-bot added created-by: Turbopack team PRs by the Turbopack team. tests Turbopack Related to Turbopack with Next.js. type: next labels Feb 9, 2026
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Feb 9, 2026

Failing test suites

Commit: 79ad382 | About building and testing Next.js

pnpm test-dev test/development/app-dir/server-component-next-dynamic-ssr-false/server-component-next-dynamic-ssr-false.test.ts (job)

  • app-dir - server-component-next-dynamic-ssr-false > should error when use dynamic ssr:false in server component (DD)
Expand output

● app-dir - server-component-next-dynamic-ssr-false › should error when use dynamic ssr:false in server component

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `app-dir - server-component-next-dynamic-ssr-false should error when use dynamic ssr:false in server component 2`

- Snapshot  - 2
+ Received  + 0

@@ -7,7 +7,5 @@
     :                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   4 | 
   5 | export default function Page() {
   6 |   return <DynamicClient />
     `----
-
-   (from ./node_modules/next/dist/build/webpack/loaders/next-swc-loader.js)

  62 |         `"  x \`ssr: false\` is not allowed with \`next/dynamic\` in Server Components. Please move it into a Client Component."`
  63 |       )
> 64 |       expect(redbox.source).toMatchInlineSnapshot(`
     |                             ^
  65 |          "./app/page.js
  66 |          Error:   x \`ssr: false\` is not allowed with \`next/dynamic\` in Server Components. Please move it into a Client Component.
  67 |             ,-[3:1]

  at Object.toMatchInlineSnapshot (development/app-dir/server-component-next-dynamic-ssr-false/server-component-next-dynamic-ssr-false.test.ts:64:29)

pnpm test-dev test/e2e/app-dir/error-on-next-codemod-comment/error-on-next-codemod-comment.test.ts (job)

  • Invalid SCSS in _document > should show a build error (DD)
Expand output

● Invalid SCSS in _document › should show a build error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Invalid SCSS in _document should show a build error 1`

- Snapshot  - 1
+ Received  + 0

  ./styles.module.scss
  CSS cannot be imported within pages/_document.js. Please move global styles to pages/_app.js.
  Location: pages/_document.js
-   (from ./node_modules/next/dist/build/webpack/loaders/error-loader.js)

  50 |           `)
  51 |         } else {
> 52 |           expect(errorSource).toMatchInlineSnapshot(`
     |                               ^
  53 |            "./styles.module.scss
  54 |            CSS cannot be imported within pages/_document.js. Please move global styles to pages/_app.js.
  55 |            Location: pages/_document.js

  at Object.toMatchInlineSnapshot (e2e/app-dir/scss/invalid-module-document/invalid-module-document.test.ts:52:31)

pnpm test-dev test/e2e/app-dir/scss/invalid-global/invalid-global.test.ts (job)

  • Valid and Invalid Global CSS with Custom App > should show a build error (DD)
Expand output

● Valid and Invalid Global CSS with Custom App › should show a build error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Valid and Invalid Global CSS with Custom App should show a build error 1`

- Snapshot  - 1
+ Received  + 0

  ./styles/global.scss
  Global CSS cannot be imported from files other than your Custom <App>. Due to the Global nature of stylesheets, and to avoid conflicts, Please move all first-party global CSS imports to pages/_app.js. Or convert the import to Component-Level CSS (CSS Modules).
  Read more: https://nextjs.org/docs/messages/css-global
  Location: pages/index.js
-   (from ./node_modules/next/dist/build/webpack/loaders/error-loader.js)

  57 |         `)
  58 |       } else {
> 59 |         expect(errorSource).toMatchInlineSnapshot(`
     |                             ^
  60 |          "./styles/global.scss
  61 |          Global CSS cannot be imported from files other than your Custom <App>. Due to the Global nature of stylesheets, and to avoid conflicts, Please move all first-party global CSS imports to pages/_app.js. Or convert the import to Component-Level CSS (CSS Modules).
  62 |          Read more: https://nextjs.org/docs/messages/css-global

  at Object.toMatchInlineSnapshot (e2e/app-dir/scss/valid-and-invalid-global/valid-and-invalid-global.test.ts:59:29)

pnpm test-dev test/e2e/app-dir/use-cache-unknown-cache-kind/use-cache-unknown-cache-kind.test.ts (job)

  • use-cache-unknown-cache-kind > should show a build error (DD)
Expand output

● use-cache-unknown-cache-kind › should show a build error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-unknown-cache-kind should show a build error 2`

- Snapshot  - 1
+ Received  + 1

@@ -2,9 +2,9 @@
  Error:   x Unknown cache kind "custom". Please configure a cache handler for this kind in the `cacheHandlers` object in your Next.js config.

     ,-[1:1]
   1 | 'use cache: custom'
     : ^^^^^^^^^^^^^^^^^^^
-  2 |
+  2 | 
   3 | export default async function Page() {
   4 |   return <p>hello world</p>
     `----"

  157 |         `)
  158 |       } else {
> 159 |         expect(errorSource).toMatchInlineSnapshot(`
      |                             ^
  160 |          "./app/page.tsx
  161 |          Error:   x Unknown cache kind "custom". Please configure a cache handler for this kind in the \`cacheHandlers\` object in your Next.js config.
  162 | 

  at Object.toMatchInlineSnapshot (e2e/app-dir/use-cache-unknown-cache-kind/use-cache-unknown-cache-kind.test.ts:159:29)

pnpm test-dev test/e2e/app-dir/scss/invalid-module-document/invalid-module-document.test.ts (job)

  • Invalid SCSS in _document > should show a build error (DD)
Expand output

● Invalid SCSS in _document › should show a build error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Invalid SCSS in _document should show a build error 1`

- Snapshot  - 1
+ Received  + 0

  ./styles.module.scss
  CSS cannot be imported within pages/_document.js. Please move global styles to pages/_app.js.
  Location: pages/_document.js
-   (from ./node_modules/next/dist/build/webpack/loaders/error-loader.js)

  50 |           `)
  51 |         } else {
> 52 |           expect(errorSource).toMatchInlineSnapshot(`
     |                               ^
  53 |            "./styles.module.scss
  54 |            CSS cannot be imported within pages/_document.js. Please move global styles to pages/_app.js.
  55 |            Location: pages/_document.js

  at Object.toMatchInlineSnapshot (e2e/app-dir/scss/invalid-module-document/invalid-module-document.test.ts:52:31)

pnpm test-start test/e2e/app-dir/use-cache-without-experimental-flag/use-cache-without-experimental-flag.test.ts (job)

  • use-cache-without-experimental-flag > should fail the build with an error (DD)
Expand output

● use-cache-without-experimental-flag › should fail the build with an error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-without-experimental-flag should fail the build with an error 1`

- Snapshot  - 1
+ Received  + 0

@@ -12,10 +12,9 @@
   4 |   return <p>hello world</p>
     `----

  Import trace for requested module:
  ./app/page.tsx
-   (from ./node_modules/next/dist/build/webpack/loaders/next-swc-loader.js)


  > Build failed because of webpack errors
  "

  75 |         `)
  76 |       } else {
> 77 |         expect(buildOutput).toMatchInlineSnapshot(`
     |                             ^
  78 |          "
  79 |          ./app/page.tsx
  80 |          Error:   x To use "use cache", please enable the feature flag \`cacheComponents\` in your Next.js config.

  at Object.toMatchInlineSnapshot (e2e/app-dir/use-cache-without-experimental-flag/use-cache-without-experimental-flag.test.ts:77:29)

pnpm test-start-turbo test/e2e/app-dir/app-prefetch/prefetching.test.ts (turbopack) (job)

  • app dir - prefetching > should immediately render the loading state for a dynamic segment when fetched from higher up in the tree (DD)
Expand output

● app dir - prefetching › should immediately render the loading state for a dynamic segment when fetched from higher up in the tree

thrown: "Exceeded timeout of 120000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

  302 |   })
  303 |
> 304 |   it('should immediately render the loading state for a dynamic segment when fetched from higher up in the tree', async () => {
      |   ^
  305 |     let act: ReturnType<typeof createRouterAct>
  306 |     const browser = await next.browser('/', {
  307 |       beforePageLoad(page) {

  at it (e2e/app-dir/app-prefetch/prefetching.test.ts:304:3)
  at Object.describe (e2e/app-dir/app-prefetch/prefetching.test.ts:11:1)

pnpm test-dev test/development/app-dir/ssr-in-rsc/ssr-in-rsc.test.ts (job)

  • react-dom/server in React Server environment > implicit react-dom/server.edge usage in app code (DD)
Expand output

● react-dom/server in React Server environment › implicit react-dom/server.edge usage in app code

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `react-dom/server in React Server environment implicit react-dom/server.edge usage in app code 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,10 +1,10 @@
  {
    "description": "  x You're importing a component that imports react-dom/server. To fix it, render or return the content directly as a Server Component instead for perf and security.",
    "environmentLabel": null,
    "label": "Build Error",
-   "source": "<FIXME-nextjs-internal-source>
+   "source": "./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?name=app%2Fexports%2Fapp-code%2Freact-dom-server-edge-implicit%2Fpage&page=%2Fexports%2Fapp-code%2Freact-dom-server-edge-implicit%2Fpage&appPaths=%2Fexports%2Fapp-code%2Freact-dom-server-edge-implicit%2Fpage&allNormalizedAppPaths=&pagePath=private-next-app-dir%2Fexports%2Fapp-code%2Freact-dom-server-edge-implicit%2Fpage.js&appDir=%2Ftmp%2Fnext-install-d0dbfdb3e407acb0fff083d784765273e7781766558a998d5e8eb9b544fcdc8f%2Fapp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=%2Ftmp%2Fnext-install-d0dbfdb3e407acb0fff083d784765273e7781766558a998d5e8eb9b544fcdc8f&isDev=true&tsconfigPath=&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!./app/exports/app-code/react-dom-server-edge-implicit/page.js?__next_edge_ssr_entry__
  Error:   x You're importing a component that imports react-dom/server. To fix it, render or return the content directly as a Server Component instead for perf and security.
    | Learn more: https://nextjs.org/docs/app/building-your-application/rendering
     ,-[1:1]
   1 | import * as ReactDOMServerEdge from 'react-dom/server'
     : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  223 |       // Expected: `./app/exports/app-code/react-dom-server-edge-implicit/page.js`
  224 |       // Observed: `./node_modules/.pnpm/next@file+..+next-repo.../page.js?__next_edge_ssr_entry__
> 225 |       await expect(browser).toDisplayRedbox(`
      |                             ^
  226 |        {
  227 |          "description": "  x You're importing a component that imports react-dom/server. To fix it, render or return the content directly as a Server Component instead for perf and security.",
  228 |          "environmentLabel": null,

  at Object.toDisplayRedbox (development/app-dir/ssr-in-rsc/ssr-in-rsc.test.ts:225:29)

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 9, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing claude/test-webpack-loader-errors-JQxSZ (79ad382) with canary (c76b0fe)

Summary

✅ 17 untouched benchmarks
⏩ 3 skipped benchmarks1

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Feb 9, 2026

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 507ms 507ms ▅█▅▁█
Cold (Ready in log) 484ms 484ms ▇▇▇▆▇
Cold (First Request) 935ms 948ms ▇██▇▇
Warm (Listen) 508ms 508ms ▁█▁▁▁
Warm (Ready in log) 482ms 480ms ▃▇▄▁▆
Warm (First Request) 367ms 365ms ▂▂█▁▂
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 455ms ▁▁▁█▁
Cold (Ready in log) 439ms 439ms ▃▁▂█▂
Cold (First Request) 1.860s 1.846s ▁▁▁█▁
Warm (Listen) 455ms 455ms ▁▁▁█▁
Warm (Ready in log) 438ms 437ms ▂▁▂█▁
Warm (First Request) 1.865s 1.867s ▁▁▁█▁

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 4.567s 4.595s ▄▃▄▂▂
Cached Build 4.519s 4.567s ▂▁▂▁▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 13.887s 13.876s ▁▁▁█▁
Cached Build 14.097s 14.077s ▁▁▁█▁
node_modules Size 467 MB 467 MB ▁▁▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles: **437 kB** → **437 kB** ⚠️ +11 B

81 files with content-based hashes (individual files not comparable between builds)

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 756 B 759 B
Total 756 B 759 B ⚠️ +3 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 451 B 452 B
Total 451 B 452 B ⚠️ +1 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.47 kB N/A -
6280-HASH.js gzip 57 kB N/A -
6335.HASH.js gzip 169 B N/A -
912-HASH.js gzip 4.53 kB N/A -
e8aec2e4-HASH.js gzip 62.5 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 256 B 254 B
main-HASH.js gzip 39.1 kB 39.1 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
262-HASH.js gzip N/A 4.53 kB -
2889.HASH.js gzip N/A 169 B -
5602-HASH.js gzip N/A 5.49 kB -
6948ada0-HASH.js gzip N/A 62.5 kB -
9544-HASH.js gzip N/A 57.6 kB -
Total 230 kB 231 kB ⚠️ +612 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 194 B
_error-HASH.js gzip 183 B 180 B 🟢 3 B (-2%)
css-HASH.js gzip 331 B 330 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 351 B 352 B
hooks-HASH.js gzip 384 B 383 B
image-HASH.js gzip 580 B 581 B
index-HASH.js gzip 260 B 260 B
link-HASH.js gzip 2.49 kB 2.49 kB
routerDirect..HASH.js gzip 320 B 319 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 315 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.97 kB 7.97 kB ✅ -1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 126 kB 126 kB
page.js gzip 249 kB 249 kB
Total 375 kB 376 kB ⚠️ +446 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 614 B 615 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 33.3 kB 33.2 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 34.9 kB 34.8 kB ✅ -158 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 733 B 735 B
Total 733 B 735 B ⚠️ +2 B
Build Cache
Canary PR Change
0.pack gzip 3.84 MB 3.85 MB 🔴 +8.53 kB (+0%)
index.pack gzip 103 kB 103 kB
index.pack.old gzip 103 kB 103 kB
Total 4.05 MB 4.05 MB ⚠️ +8.05 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 315 kB 315 kB
app-page-exp..prod.js gzip 167 kB 167 kB
app-page-tur...dev.js gzip 315 kB 315 kB
app-page-tur..prod.js gzip 167 kB 167 kB
app-page-tur...dev.js gzip 312 kB 312 kB
app-page-tur..prod.js gzip 166 kB 166 kB
app-page.run...dev.js gzip 312 kB 312 kB
app-page.run..prod.js gzip 166 kB 166 kB
app-route-ex...dev.js gzip 70.5 kB 70.5 kB
app-route-ex..prod.js gzip 49 kB 49 kB
app-route-tu...dev.js gzip 70.5 kB 70.5 kB
app-route-tu..prod.js gzip 49 kB 49 kB
app-route-tu...dev.js gzip 70.1 kB 70.1 kB
app-route-tu..prod.js gzip 48.8 kB 48.8 kB
app-route.ru...dev.js gzip 70.1 kB 70.1 kB
app-route.ru..prod.js gzip 48.7 kB 48.7 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 43.2 kB 43.2 kB
pages-api-tu..prod.js gzip 32.9 kB 32.9 kB
pages-api.ru...dev.js gzip 43.2 kB 43.2 kB
pages-api.ru..prod.js gzip 32.8 kB 32.8 kB
pages-turbo....dev.js gzip 52.5 kB 52.5 kB
pages-turbo...prod.js gzip 39.4 kB 39.4 kB
pages.runtim...dev.js gzip 52.5 kB 52.5 kB
pages.runtim..prod.js gzip 39.4 kB 39.4 kB
server.runti..prod.js gzip 62.7 kB 62.7 kB
Total 2.8 MB 2.8 MB ⚠️ +342 B
📝 Changed Files (4 files)

Files with changes:

  • app-page-exp..ntime.dev.js
  • app-page-tur..ntime.dev.js
  • app-page-tur..ntime.dev.js
  • app-page.runtime.dev.js
View diffs
app-page-exp..ntime.dev.js

Diff too large to display

app-page-tur..ntime.dev.js

Diff too large to display

app-page-tur..ntime.dev.js

Diff too large to display

app-page.runtime.dev.js

Diff too large to display

@sokra sokra force-pushed the claude/test-webpack-loader-errors-JQxSZ branch from 7bc5926 to 93cd56a Compare February 9, 2026 10:43
Copy link
Member Author

sokra commented Feb 9, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@sokra sokra force-pushed the claude/test-webpack-loader-errors-JQxSZ branch from 93cd56a to 2bdeafb Compare February 9, 2026 12:34
claude and others added 9 commits February 10, 2026 11:09
Test that errors thrown in webpack loaders surface the source file path
and error message in the CLI output. Covers four cases:
- Loader throws an Error object
- Loader throws a plain string (NonErrorEmittedError)
- Loader has an unhandled rejected Promise
- Loader has a setTimeout that throws after completion

https://claude.ai/code/session_01XnHv9KVqYRDLDti1q6vni4
Add turbopack.rules config mapping each .data file to its corresponding
loader, and remove the IS_TURBOPACK_TEST skip so the tests run for both
webpack and Turbopack.

https://claude.ai/code/session_01XnHv9KVqYRDLDti1q6vni4
Turbopack handles unhandled rejections and setTimeout errors differently
from webpack when running loaders:
- Unhandled promise rejections surface later attributed to a different file
- setTimeout errors thrown after loader completion are swallowed entirely

https://claude.ai/code/session_01XnHv9KVqYRDLDti1q6vni4
- Add loaders/error-loader path assertion for Turbopack (which preserves
  loader paths in stack traces)
- Use loaders/ prefix for promise-error and timeout-error assertions to
  verify the loader path is actually present, not just matching the name
  in the error message
- Document that string-error case loses loader path in both modes:
  webpack strips it via format-webpack-messages, turbopack only shows
  internal frames for string throws
- Document that webpack strips loader path for Error throws via
  format-webpack-messages filtering "Module build failed (from ...)" lines

https://claude.ai/code/session_01XnHv9KVqYRDLDti1q6vni4
- Preserve loader paths in format-webpack-messages.ts instead of stripping
  "Module build failed (from ...)" lines entirely
- Add unhandledRejection handler in turbopack IPC to catch Promise.reject
  errors from loaders
- Wrap non-Error throws (strings) with synthetic stack containing loader
  paths in turbopack webpack-loaders.ts
- Delay loader resolution by one event loop turn to catch deferred errors
  (setTimeout throws, unhandled rejections) before sending IPC end message
- Migrate webpack-loader-errors tests from test/development/ to test/e2e/
  with proper e2e patterns (isNextDev guard, skipDeployment, error overlay)

https://claude.ai/code/session_01XnHv9KVqYRDLDti1q6vni4
Instead of placing the `(from ./loader.js)` line where the original
"Module build failed" header was, extract it and append at the end.
This avoids shifting line positions which broke sass error detection
and snapshot tests.
…Turbopack loader errors

- Add no-stack-error-loader (throws Error with stack=undefined) and
  fs-error-loader (throws ENOENT via fs.readFileSync) test cases
- Turbopack webpack-loaders.ts: append "(from <loader-path>)" to all
  error messages (both Error instances and string throws), matching
  webpack's format-webpack-messages style
- Restructure tests: CLI tests for edge cases are Turbopack-only since
  webpack only logs errors[0] per compilation; overlay tests use generic
  assertions since build errors accumulate globally
Webpack error messages now include `(from .../loader.js)` attribution
lines with dynamic pnpm content-addressable store hashes. Normalize
these paths in test assertions and update inline snapshots to include
the attribution lines with clean paths.
Filter out `(from ...)` loader attribution when the loader path is
inside next/dist/. Internal loaders like next-swc-loader and
sass-loader are noise for users. Third-party loader paths are still
shown. Revert snapshot additions that included internal loader paths.
@sokra sokra force-pushed the claude/test-webpack-loader-errors-JQxSZ branch from 2bdeafb to 79ad382 Compare February 10, 2026 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by: Turbopack team PRs by the Turbopack team. tests Turbopack Related to Turbopack with Next.js. type: next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants