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.
Symptom
Section titled “Symptom”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.
Related — the other dev-only breakage this week (different cause)
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.