Title: devtools-vite: source injection silently yields zero data-tsd-source attributes (AST child-key cache poisoned by regex literals) · Issue #523 · TanStack/devtools · GitHub
Open Graph Title: devtools-vite: source injection silently yields zero data-tsd-source attributes (AST child-key cache poisoned by regex literals) · Issue #523 · TanStack/devtools
X Title: devtools-vite: source injection silently yields zero data-tsd-source attributes (AST child-key cache poisoned by regex literals) · Issue #523 · TanStack/devtools
Description: TanStack Devtools version @tanstack/devtools-vite@0.8.5 transitive @tanstack/devtools-bundler-core@0.1.3 @tanstack/react-devtools@0.10.12 (transitive @tanstack/devtools@0.14.2) Vite 8.2.2, Astro 7.2.9 (Astro drives Vite here; I could not...
Open Graph Description: TanStack Devtools version @tanstack/devtools-vite@0.8.5 transitive @tanstack/devtools-bundler-core@0.1.3 @tanstack/react-devtools@0.10.12 (transitive @tanstack/devtools@0.14.2) Vite 8.2.2, Astro 7....
X Description: TanStack Devtools version @tanstack/devtools-vite@0.8.5 transitive @tanstack/devtools-bundler-core@0.1.3 @tanstack/react-devtools@0.10.12 (transitive @tanstack/devtools@0.14.2) Vite 8.2.2, Astro 7....
Opengraph URL: https://github.com/TanStack/devtools/issues/523
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"devtools-vite: source injection silently yields zero data-tsd-source attributes (AST child-key cache poisoned by regex literals)","articleBody":"### TanStack Devtools version\n\n- `@tanstack/devtools-vite@0.8.5`\n- transitive `@tanstack/devtools-bundler-core@0.1.3`\n- `@tanstack/react-devtools@0.10.12` (transitive `@tanstack/devtools@0.14.2`)\n- Vite `8.2.2`, Astro `7.2.9` (Astro drives Vite here; I could not reproduce with plain Vite)\n- Node `26.7.0`, Linux\n\n### Describe the bug and the steps to reproduce it\n\nThe \"Go to Source\" / source inspector feature injects **zero** `data-tsd-source`\nattributes. There is no browser console warning and nothing in the Vite dev\nserver log, so the feature just silently does nothing.\n\nRoot cause, from reading `@tanstack/devtools-bundler-core/dist/esm/ast-utils.js`.\n`getChildKeys(node)` memoises the child-bearing keys of each AST node type in a\n**module-level** `childKeysCache` Map, seeded from the *first* instance of that\ntype it ever sees:\n\n```js\nfor (const key in node) {\n if (key === \"type\" || key === \"start\" || key === \"end\") continue;\n if (typeof node[key] === \"object\") keys.push(key);\n}\n```\n\nA regex literal (`/abc/g`) is an oxc `Literal` whose `value` is an **object**, so\n`value` is cached as a child key for the type `Literal`. Every subsequent\n*string* `Literal` then reaches:\n\n```js\n} else if (\"type\" in value) callback(value);\n```\n\nwith `value` being a string, and throws:\n\n```\nTypeError: Cannot use 'in' operator to search for 'type' in use client\n at forEachChild (.../@tanstack/devtools-bundler-core/dist/esm/ast-utils.js:31:21)\n```\n\n`\"use client\"` is simply the first string literal in that particular file; the\nthrow happens for any string literal. `addSourceToJsx()` wraps its whole body in\n`try { ... } catch (e) { return; }`, so the TypeError is swallowed and the\nfunction returns `undefined` — no attributes, no log, no warning.\n\nBecause the cache is module-level and shared across every file and every call,\na single regex literal anywhere in the module graph disables source injection\nfor every string literal parsed afterwards. That is why this reproduces in a\nreal dev server but not in an isolated unit test.\n\n### Minimal reproduction\n\nTwo separate `node` processes, same target file (any `.tsx` file with JSX):\n\n```js\nimport { addSourceToJsx } from '@tanstack/devtools-bundler-core'\n\n// Case A — fresh cache: works\naddSourceToJsx(heroCode, heroPath, {}) // -> transformed, N attributes injected\n\n// Case B — parse a regex literal first, then the same file: returns undefined\naddSourceToJsx('const r = /abc/g;\\nexport default r;\\n', regexPath, {})\naddSourceToJsx(heroCode, heroPath, {}) // -> undefined\n```\n\nRun the two cases in **separate processes**. Case A injects the attributes,\nCase B returns `undefined`.\n\nObserved in a real app: a component that reported 36 injected attributes in\nisolation injected 0 once the dev server had processed the rest of the graph.\n\n### Expected behavior\n\nSource injection should not depend on which files were parsed earlier. And a\nfailure inside `addSourceToJsx` should at least be logged rather than swallowed,\nso the feature cannot fail completely silently.\n\n### Suggested fix\n\nGuard the non-array branch the same way the array branch already is:\n\n```diff\n- } else if (\"type\" in value) callback(value);\n+ } else if (typeof value === \"object\" && \"type\" in value) callback(value);\n```\n\nWith that guard, Case B injects the attributes again. A more thorough fix would\nmake `getChildKeys` key the cache on the *shape* of the node (or only record\nkeys whose value is a node or an array of nodes) and drop the bare `catch`.\n\nI am carrying this as a local `patch-package` patch for now.\n\n### Do you intend to try to help solve this bug with your own PR?\n\nMaybe, I'll investigate and start debugging\n\n### Terms & Code of Conduct\n\n- [x] I agree to follow this project's Code of Conduct\n- [x] I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not get fixed and this issue may even be closed.\n","author":{"url":"https://github.com/nencodev","@type":"Person","name":"nencodev"},"datePublished":"2026-09-01T03:14:10Z","url":"https://github.com/TanStack/devtools/issues/523"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:07a9a601-071b-ff68-fec3-80792b24c700 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E81A:153508:41CD03B:55F9150:6AF9ACB3 |
| html-safe-nonce | 9c7dadce2c6b914787669a9947fa5408270c38eef8a46965cd20b91c2447a453 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFODFBOjE1MzUwODo0MUNEMDNCOjU1RjkxNTA6NkFGOUFDQjMiLCJ2aXNpdG9yX2lkIjoiNzg0NDI1NDUzNTIxMDYwOTg0MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | ccbf7306b6900a7fc67cfc7c74e0039e5ca67e7c5a08246a3c3292e7ac2010cd |
| hovercard-subject-tag | issue:5307384566 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/TanStack/devtools/523/issue_layout |
| twitter:image | https://opengraph.githubassets.com/d6bb4e6f7295cabfb84e9e318a2965f0115aeb13efde4de025b3ae9aec9f1a12/TanStack/devtools/issues/523 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/d6bb4e6f7295cabfb84e9e318a2965f0115aeb13efde4de025b3ae9aec9f1a12/TanStack/devtools/issues/523 |
| og:image:alt | TanStack Devtools version @tanstack/devtools-vite@0.8.5 transitive @tanstack/devtools-bundler-core@0.1.3 @tanstack/react-devtools@0.10.12 (transitive @tanstack/devtools@0.14.2) Vite 8.2.2, Astro 7.... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | nencodev |
| hostname | github.com |
| expected-hostname | github.com |
| None | 612d3e6ffd693e7ea8d9fcf452370995872baef31d825b1fedef704cd3d24ac7 |
| turbo-cache-control | no-preview |
| go-import | github.com/TanStack/devtools git https://github.com/TanStack/devtools.git |
| octolytics-dimension-user_id | 72518640 |
| octolytics-dimension-user_login | TanStack |
| octolytics-dimension-repository_id | 1026402761 |
| octolytics-dimension-repository_nwo | TanStack/devtools |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1026402761 |
| octolytics-dimension-repository_network_root_nwo | TanStack/devtools |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 072e34035c13c31543fba9f025cbbbda4210dae4 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width