nitrojs / nitrojs/nitro

nitro dev returns 500 and crashes error renderer when using Better Auth (`Cannot read properties of undefined (reading 'replace')`), while built server returns expected 401

Open
#4,050 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug v3
Dominant language
TypeScript
Stars
11.2k
Forks
899
Avg merge
2d 24m
Merged PRs (30d)
40

Description

Environment

Environment

  • Nitro: 3.0.1-alpha.2 (also reproduced on 3.0.1-alpha.1)
  • H3: 2.0.1-rc.14 (and 2.0.1-rc.5 when testing alpha.1)
  • Node.js: v25.6.1
  • pnpm: 10.29.3
  • OS: macOS (darwin-arm64)
nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  serverDir: "./",
});
Route wiring
// routes/api/auth/[...all].ts
import { defineHandler } from "nitro/h3";
import { auth } from "~/auth";

export default defineHandler((event) => {
  return auth.handler(event.req);
});
Reproduction

No public minimal reproduction repo yet.

Reason:

  • This setup currently depends on a configured Better Auth server and a live PostgreSQL database.
  • The Nitro starter sandboxes linked in the template are not currently aligned with the Nitro v3 alpha stack used in this project.
Current reproduction steps (private/local project)
  1. Configure env vars (DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL, BETTER_AUTH_TRUSTED_ORIGINS).
  2. Start dev server:
pnpm dev
  1. Call sign-in endpoint for a non-existing user:
curl -i 'http://localhost:3000/api/auth/sign-in/email' \
  -X POST \
  -H 'Origin: http://localhost:3000' \
  -H 'Content-Type: application/json' \
  --data '{"email":"test@test.cl","password":"test12345"}'
  1. Observe 500 in dev with stack trace including:
  • TypeError: fetch failed
  • Error: expected non-null body source
  • TypeError: Cannot read properties of undefined (reading 'replace')
  1. Build and run production-like server:
pnpm build
node .output/server/index.mjs
  1. Run the same curl request and observe expected 401 INVALID_EMAIL_OR_PASSWORD.

If needed, I can prepare and share a public reproduction repo based on Nitro starter + local Postgres container.

Describe the bug

In nitro dev, auth requests that should return a normal unauthorized response (401) are surfaced as 500 due to a crash in Nitro's dev error rendering path.

The same request works correctly in production-like runtime (pnpm build + node .output/server/index.mjs), which returns:

{"code":"INVALID_EMAIL_OR_PASSWORD","message":"Invalid email or password"}

So the issue appears to be specific to Nitro dev mode error handling/rendering rather than the auth logic itself.

Expected behavior

Dev runtime should return the same functional response as production runtime for this request (401 invalid credentials), without crashing the error renderer.

Actual behavior

In dev, endpoint returns 500 and logs include:

  • Better Auth expected log: User not found
  • Undici error: TypeError: fetch failed with cause Error: expected non-null body source
  • Nitro dev renderer crash: TypeError: Cannot read properties of undefined (reading 'replace')
Additional context

I tested with two separate Postgres providers:

  • Supabase
  • Neon

Same behavior in local dev.

  • I tested by removing custom database field mapping from my Better Auth config.
    Same behavior in local dev.

  • I tested in another existing backend project that already uses Better Auth in production.
    Same behavior locally; hosted environments still work.

  • Hosting provider (Railway) environments (dev, staging, prod) do not show this failure, and auth endpoints behave correctly there.

This points to a local dev runtime issue, likely in Nitro dev mode and/or dev error formatting path.

Logs
2026-02-17T23:21:34.569Z ERROR [Better Auth]: User not found { email: 'test@test.cl' }
[TypeError: fetch failed] {
  cause: [TypeError: fetch failed] {
    [cause]: Error: expected non-null body source
        at makeNetworkError (node:internal/deps/undici/undici:10797:35)
        at httpNetworkOrCacheFetch (node:internal/deps/undici/undici:12629:20)
        at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
        at async httpFetch (node:internal/deps/undici/undici:12430:37)
        at async mainFetch (node:internal/deps/undici/undici:12191:24)
  },
  status: 500,
  statusText: undefined,
  headers: undefined,
  data: undefined,
  body: undefined,
  unhandled: true
}
TypeError: Cannot read properties of undefined (reading 'replace')
    at #getRelativeFileName (.../node_modules/nitro/dist/node_modules/youch/build/chunk-*.js:*)
    at #printStackFrame (.../node_modules/nitro/dist/node_modules/youch/build/chunk-*.js:*)
    at .../node_modules/nitro/dist/node_modules/youch/build/chunk-*.js:*
    at Array.map (<anonymous>)
    at ErrorStack.toANSI (.../node_modules/nitro/dist/node_modules/youch/build/chunk-*.js:*)
    at #tmplToANSI (.../node_modules/nitro/dist/node_modules/youch/build/index.js:*)
    at Object.children (.../node_modules/nitro/dist/node_modules/youch/build/index.js:*)
    at async Layout.toANSI (.../node_modules/nitro/dist/node_modules/youch/build/chunk-*.js:*)
    at async Templates.toANSI (.../node_modules/nitro/dist/node_modules/youch/build/index.js:*)
    at async defaultHandler (.../node_modules/nitro/dist/_chunks/dev.mjs:*)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the request with pnpm dev and compare it with pnpm build followed by node .output/server/index.mjs. Trace the dev error path from nitro/dist/_chunks/dev.mjs into the Youch renderer, especially #getRelativeFileName and ErrorStack.toANSI; done means the dev request returns the expected 401 response without the renderer crash.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, postgresql, typescript
Domain
backend, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.