Repository: vercel/next.js
Pull request: Enable backtraces in turbopack integration tests

## Enable Rust backtraces in CI tests

### What?
Added `RUST_BACKTRACE=1` environment variable to all Turbopack-related test workflows.

### Why?
This change enables detailed Rust backtraces when Turbopack encounters errors during CI tests, making it easier to diagnose and fix issues that occur in the Rust components.

Notably, some assertions/panics are about detecting race conditions, e.g.
```
thread 'tokio-runtime-worker' (1056161) panicked at turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs:426:13:
Concurrent task lock acquisition detected. This is not allowed and indicates a bug. It can lead to deadlocks.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

Rather than painfully attempting to reproduce locally we can just run with the env var all the time and perhaps that will be enough to figure out rare issues

Changed files:
filename: .github/workflows/build_and_test.yml
patch: @@ -256,6 +256,7 @@ jobs:
         export NEXT_TEST_MODE=dev
         export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
         export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
+        export RUST_BACKTRACE=1
 
         node run-tests.js \
           --test-pattern '^(test\/(development|e2e))/.*\.test\.(js|jsx|ts|tsx)$' \
@@ -287,6 +288,7 @@ jobs:
         export TURBOPACK_DEV=1
         export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
         export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
+        export RUST_BACKTRACE=1
 
         node run-tests.js \
           --timings \
@@ -318,6 +320,7 @@ jobs:
         export NEXT_TEST_MODE=start
         export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
         export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
+        export RUST_BACKTRACE=1
 
         node run-tests.js --timings -g ${{ matrix.group }} --type production
       stepName: 'test-turbopack-production-react-${{ matrix.react }}-${{ matrix.group }}'
@@ -346,6 +349,7 @@ jobs:
         export TURBOPACK_BUILD=1
         export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
         export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
+        export RUST_BACKTRACE=1
 
         node run-tests.js \
           --timings \

filename: .github/workflows/turbopack-nextjs-build-integration-tests.yml
patch: @@ -13,7 +13,7 @@ jobs:
       name: turbopack-production
       test_type: production
       run_before_test: |
-        export IS_TURBOPACK_TEST=1 TURBOPACK_BUILD=1
+        export IS_TURBOPACK_TEST=1 TURBOPACK_BUILD=1 RUST_BACKTRACE=1
       # Failing tests take longer (due to timeouts and retries). Since we have
       # many failing tests, we need smaller groups and longer timeouts, in case
       # a group gets stuck with a cluster of failing tests.

filename: .github/workflows/turbopack-nextjs-dev-integration-tests.yml
patch: @@ -13,5 +13,5 @@ jobs:
       name: turbopack-development
       test_type: development
       run_before_test: |
-        export IS_TURBOPACK_TEST=1 TURBOPACK_DEV=1
+        export IS_TURBOPACK_TEST=1 TURBOPACK_DEV=1 RUST_BACKTRACE=1
     secrets: inherit

filename: turbopack/crates/turbopack-ecmascript-plugins/src/transform/swc_ecma_transform_plugins.rs
patch: @@ -299,9 +299,22 @@ impl CustomTransformer for SwcEcmaTransformPluginsTransformer {
                         Err(e) => {
                             use turbopack_core::issue::IssueExt;
 
+                            // Format the error chain without backtrace.
+                            // Using `{:?}` would include the backtrace when
+                            // RUST_BACKTRACE=1, which is not useful in
+                            // user-facing error messages.
+                            let mut description = e.to_string();
+                            let mut causes = e.chain().skip(1).peekable();
+                            if causes.peek().is_some() {
+                                description.push_str("\n\nCaused by:");
+                                for (i, cause) in causes.enumerate() {
+                                    description.push_str(&format!("\n    {i}: {cause}"));
+                                }
+                            }
+
                             SwcEcmaTransformFailureIssue {
                                 file_path: ctx.file_path.clone(),
-                                description: StyledString::Text(format!("{:?}", e).into()),
+                                description: StyledString::Text(description.into()),
                             }
                             .resolved_cell()
                             .emit();