Files
Leo Camus ccea5fd23e [Flight & DevTools] Strip the whole "async " prefix from V8 stack frame names (#37608)
## Summary

V8 prefixes async call sites with `async ` when it prints a stack, like
this:

```
Error: boom
    at inner (/tmp/asy.js:1:44)
    at async outerName (/tmp/asy.js:2:30)
```

`parseStackTraceFromChromeStack` captures `async outerName` as the frame
name and strips the prefix here:

```js
} else if (name.startsWith('async ')) {
  name = name.slice(5);
  isAsync = true;
}
```

`'async '` is six characters, so `slice(5)` leaves the space behind and
the frame name comes back as `' outerName'` rather than `'outerName'`.

I noticed it while reading the parser, and it is not purely cosmetic:
that name is the first element of the `ReactFunctionLocation` returned
by `extractLocationFromComponentStack` and
`extractLocationFromOwnerStack`, which `backend/fiber/renderer.js`
stores as `instance.source`. Any async component whose frame reaches
that path is recorded under a name with a stray leading space.

The same line exists in
`packages/react-server/src/ReactFlightStackConfigV8.js`, which the
DevTools file is a copy of. After review I fixed it in this PR as well,
in a second commit. There it only matters on the fallback path that
parses an already formatted stack string, when the error's `stack` was
read or assigned before React reaches it. #37130 is open on that file
too, but it does not touch these lines.

## How did you test this change?

I first confirmed the format V8 actually emits, rather than assuming it:

```
$ node -e 'async function inner(){await null;throw new Error("boom")}
async function outerName(){await inner()}
outerName().catch(e=>console.log(e.stack))'
Error: boom
    at inner ([eval]:1:52)
    at async outerName ([eval]:2:33)
```

Then I added a case to the existing `extractLocationFromComponentStack`
block in `utils-test.js`. Against `main` it fails with exactly the
leading space:

```
  ● utils › extractLocationFromComponentStack › should strip the async prefix from a frame name

    - Expected  - 1
    + Received  + 1

      Array [
    -   "Comments",
    +   " Comments",
        "https://react.dev/_next/static/chunks/848-122f91e9565d9ffa.js",
        5,
        9236,
      ]
```

With the one-character fix applied:

```
$ yarn test --build --project=devtools -r=experimental utils-test
PASS packages/react-devtools-shared/src/__tests__/utils-test.js
Tests:       63 passed, 63 total
```

I also ran the whole DevTools project before and after to check I was
not moving anything else. Both runs end at `9 failed, 4 failed suites`,
the same test names each time (`componentStacks`, `console`,
`inspectedElement`, `legacy/inspectElement`), so those failures are
pre-existing on `main` in my environment and unrelated to this change.
The only difference between the two runs is my new test: 586 passed
before, 587 after.

For the Flight side I added `ReactFlightStackConfigV8-test.js`, which
assigns a formatted stack to an error and checks what `parseStackTrace`
returns. Against `main` it fails with the same leading space (`"
outerName"`); with the fix it passes on stable and experimental in
development. It is gated to `__DEV__` because that fallback goes through
the DEV-only stack cache. `ReactFlightServer-test` and
`ReactFlightAsyncDebugInfo-test` still pass next to it (23 tests).

`prettier` and `eslint` are clean on all changed files. `yarn flow
dom-node` reported no errors for the DevTools commit; I did not rerun
Flow after the one-character Flight change.

AI tools used
2026-09-13 11:30:57 +01:00
..
2025-08-21 11:15:34 -04:00
2022-03-16 11:37:10 -04:00

This directory contains code shared between several DevTools packages:

  • /packages/react-devtools-core
  • /packages/react-devtools-extensions
  • /packages/react-devtools-inline

It is not published or released anywhere directly.