Description
Describe the bug
Rendering any @solidjs/meta tag (<Title>, <Meta>, <Link>) during SSR in dev mode throws NoOwnerError:
at getContext (node_modules/solid-js/dist/server.js:104:21)
at useContext (node_modules/solid-js/dist/server.js:1476:12)
at headTag (node_modules/@solidjs/meta/dist/index.js:36:19)
at Title (node_modules/@solidjs/meta/dist/index.js:79:31)
at PageMetaTags (src/components/shared/PageMetaTags/index.tsx:32:34)
at Home (src/components/pages/Home/index.tsx:51:41)
at createMemo.sync (node_modules/solid-js/dist/server.dev.js:1622:18)
at pull (node_modules/solid-js/dist/server.dev.js:410:15)
at createSyncMemo (node_modules/solid-js/dist/server.dev.js:429:7)
Note that the same stack contains frames from both dist/server.js and dist/server.dev.js.
Environment
solid-js,@solidjs/web—2.0.0-rc.7@solidjs/meta—1.0.0-next.2@solidjs/router—2.0.0-next.23@solidjs/vite-plugin—3.0.0-next.40- Node 24.0.1, Vite 8.2.2, macOS
Root cause
solid-js ships separate dev and prod builds behind the development export condition:
$ node --input-type=module -e "console.log(await import.meta.resolve('solid-js'))"
.../solid-js/dist/server.js
$ node --conditions development --input-type=module -e "console.log(await import.meta.resolve('solid-js'))"
.../solid-js/dist/server.dev.js
@solidjs/vite-plugin puts solid-js and @solidjs/web into ssr.noExternal, plus every package vitefu recognises as a Solid package — recognition is based on the solid export condition. @solidjs/meta does not have one:
"exports": { ".": "./dist/index.js" }So it stays external. Node imports it natively, without the development condition, and it gets dist/server.js, while the app runs on dist/server.dev.js. currentOwner is module-level state, so there are now two independent owner stacks: the router sets the owner in the dev instance, the prod instance still sees null, and getContext throws.
This only surfaced with the <Head> group support, where headTag started calling useContext(HeadGroupContext). Before that @solidjs/meta only called useHead from @solidjs/web, which does not read module-level owner state, so the duplicate instance was harmless.
Steps to reproduce
- Vite +
@solidjs/vite-pluginapp with SSR enabled. - Render
<Title>from@solidjs/metain any route component. - Run
vite devand request the page.
Expected behavior
@solidjs/meta resolves the same solid-js build as the rest of the app and <Title> renders.
Workaround
// vite.config.ts
ssr: {
noExternal: ['@solidjs/meta'],
},This makes Vite process the package, so the development condition applies and both end up on dist/server.dev.js.
Suggested resolution
Add a solid export condition to @solidjs/meta (like solid-js and @solidjs/web have) so vitefu detects it and the plugin inlines it automatically. Any other package that imports solid-js and is left external will hit the same problem.
Reported with Claude Code (Opus 5).
Activity