Skip to content

B-KDP6-h3-duplication-breaks-dev-post-routes

Found while migrating learn_web onto @sksizer/markdown-ui (PR 8 of the markdown-editing program, task T-BLHH-learn-web-editor-markdown-ui). It blocks nothing there — the Playwright suite runs against the built server — but it makes the app’s dev server useless for anything that writes.

Under nuxt dev in solutions/augmented/apps/learn_web, every POST endpoint fails:

event.req.headers.get is not a function
at readBody (node_modules/.bun/h3@2.0.1-rc.25+.../h3.mjs:1256:40)
at Object.handler (layers/books/server/api/books/v2/content/[contentId].post.ts:24:0)
at (node_modules/.bun/h3@1.15.11/node_modules/h3/dist/index.mjs:1942:43)

Saving content, creating a book, writing a tree, writing SQL — all of them.

Four copies of h3 are installed: 1.15.11 plus three 2.0.1-rc.*. learn_web declares none of them; they are all transitive. Under nuxt dev, Vite’s SSR resolution takes readBody from h3 v2, which expects a Web Request, while the event handed to it comes from h3 v1, whose headers is a plain object. The two majors meet inside one request.

The built server resolves h3 consistently and saves work there — verified by hand (POST /api/books/v2/content/q9tSxGW4 returns 200 and the file is byte-identical afterwards).

A manifest change: pin or dedupe h3 across the workspace so one major is installed. Deliberately out of scope for PR 8, which changed no dependency resolution beyond its own markdown packages.

Section titled “Related — the other dev-only breakage this week (different cause)”

optimizeDeps.include in the @sksizer/markdown-ui layer reached the production build but not nuxt dev, so every file:-wired host of the layer 500s in dev on a CJS export (debug) the layer names precisely to prevent it. That one is root-caused and fixed: the layer declared optimizeDeps.include with bare package names, and Vite resolves those against the CONSUMING app’s root, so for a file:-installed layer all three entries were dropped and debug was served as CJS. PR 7 confirmed it by fetching the module through Vite and seeing exports.formatArgs with no ESM export, then fixed it with the SDF shape.

It is recorded here only because two dev-only breakages in one week is worth someone seeing together. The mechanisms are different: that one was specifier resolution in a layer’s own config, this one is a genuine dependency duplication in the install tree. Nothing here should be read as a shared root cause — do not go looking for a config-merge bug.


← Back to Backlog