[GH-ISSUE #1274] Next.js App Router: TypeError 'n.get is not a function' in auth handlers #8669

Closed
opened 2026-04-13 03:49:32 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @benjamindell on GitHub (Jan 23, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/1274

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Description

When using better-auth with Next.js App Router, the auth handlers (both POST and GET) can throw a TypeError indicating that 'n.get is not a function'. This occurs during the OAuth flow, specifically with social login providers.

Environment

  • Next.js (App Router)
  • better-auth (latest version)
  • Deployment: AWS Lambda/Edge (based on stack trace)
  • Node.js version: [your Node version]

Error Message

TypeError: n.get is not a function
at h (/var/task/.next/server/chunks/1684.js:17:9378)
at tv (/var/task/.next/server/chunks/1684.js:100:6421)
at Object.onRequest (/var/task/.next/server/chunks/1684.js:100:11550)
at handler (/var/task/.next/server/chunks/1684.js:100:30681)
at Object.handler (/var/task/.next/server/chunks/1684.js:100:16248)

Steps to Reproduce

  1. Set up better-auth with Next.js App Router
  2. Implement social login (e.g., Google OAuth)
  3. Click "Login with Google"
  4. Select Google account
  5. Error occurs during callback

Current vs. Expected behavior

Workaround

The issue can be resolved by reconstructing the Request object in the route handlers:

// app/api/auth/[...all]/route.ts
import { headers } from 'next/headers'
export async function POST(request: Request) {
const headersList = headers()
const modifiedRequest = new Request(request.url, {
method: request.method,
headers: new Headers(headersList),
body: request.body,
duplex: 'half', // Required for POST requests with body
// ... other request properties
})
return originalPost(modifiedRequest)
}

What version of Better Auth are you using?

1.1.14

Provide environment information

AWS / Cloudfront / Lambda
NextJS 15.1.6

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { AuthContext, betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"

import { db } from "@/lib/db/connection"

import { logError } from "../utils/errors"

const requiredEnvVar = (name: string): string => {
    const value = process.env[name]
    if (!value) {
        throw new Error(`Missing required environment variable: ${name}`)
    }
    return value
}

export const auth = betterAuth({
    database: drizzleAdapter(db, {
        provider: "pg",
    }),
    baseURL: requiredEnvVar("BETTER_AUTH_URL"),
    basePath: "/api/auth",
    trustedOrigins: [requiredEnvVar("BETTER_AUTH_URL")],
    onAPIError: {
        throw: true, // This will help surface errors during development
        onError: async (error: unknown, ctx: AuthContext) => {
            const errorContext = {
                error,
                baseURL: ctx.baseURL,
                session: ctx.session,
                trustedOrigins: ctx.trustedOrigins,
                request: {
                    url: ctx.options.baseURL,
                    method: ctx.options.basePath,
                },
            }
            console.log("Auth API error", errorContext)
            await logError("Auth API error", errorContext)
        },
    },
    user: {
        modelName: "UserTable",
        additionalFields: {
            subscriptionStatus: { type: "string", required: false, input: false },
            subscriptionPlanId: { type: "string", required: false, input: false },
        },
    },
    account: {
        modelName: "AccountTable",
        accountLinking: { enabled: true },
    },
    session: {
        modelName: "SessionTable",
    },
    verification: {
        modelName: "VerificationTokenTable",
    },
    emailAndPassword: {
        enabled: true,
        requireEmailVerification: true,
    },
    emailVerification: {
        sendVerificationEmail: async ({ user, url, token }, request) => {
        },
    },
    socialProviders: {
        google: {
            clientId: requiredEnvVar("GOOGLE_CLIENT_ID"),
            clientSecret: requiredEnvVar("GOOGLE_SECRET_ID"),
        },
    },
})

Additional context

Additional Context

  • The error seems related to how Next.js App Router modifies the Request object
  • The issue appears during both the initial auth request and the OAuth callback
  • The temp workaround ensures a standard-compliant Request object is passed to better-auth

Questions

  1. Is this expected behavior with Next.js App Router?
  2. Should better-auth handle Request object normalization internally?
  3. Could this be documented in the better-auth docs for Next.js App Router users?
Originally created by @benjamindell on GitHub (Jan 23, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/1274 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ## Description When using better-auth with Next.js App Router, the auth handlers (both POST and GET) can throw a TypeError indicating that 'n.get is not a function'. This occurs during the OAuth flow, specifically with social login providers. ### Environment - Next.js (App Router) - better-auth (latest version) - Deployment: AWS Lambda/Edge (based on stack trace) - Node.js version: [your Node version] ### Error Message ``` TypeError: n.get is not a function at h (/var/task/.next/server/chunks/1684.js:17:9378) at tv (/var/task/.next/server/chunks/1684.js:100:6421) at Object.onRequest (/var/task/.next/server/chunks/1684.js:100:11550) at handler (/var/task/.next/server/chunks/1684.js:100:30681) at Object.handler (/var/task/.next/server/chunks/1684.js:100:16248) ``` ### Steps to Reproduce 1. Set up better-auth with Next.js App Router 2. Implement social login (e.g., Google OAuth) 3. Click "Login with Google" 4. Select Google account 5. Error occurs during callback ### Current vs. Expected behavior ### Workaround The issue can be resolved by reconstructing the Request object in the route handlers: ``` // app/api/auth/[...all]/route.ts import { headers } from 'next/headers' export async function POST(request: Request) { const headersList = headers() const modifiedRequest = new Request(request.url, { method: request.method, headers: new Headers(headersList), body: request.body, duplex: 'half', // Required for POST requests with body // ... other request properties }) return originalPost(modifiedRequest) } ``` ### What version of Better Auth are you using? 1.1.14 ### Provide environment information ```bash AWS / Cloudfront / Lambda NextJS 15.1.6 ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { AuthContext, betterAuth } from "better-auth" import { drizzleAdapter } from "better-auth/adapters/drizzle" import { db } from "@/lib/db/connection" import { logError } from "../utils/errors" const requiredEnvVar = (name: string): string => { const value = process.env[name] if (!value) { throw new Error(`Missing required environment variable: ${name}`) } return value } export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", }), baseURL: requiredEnvVar("BETTER_AUTH_URL"), basePath: "/api/auth", trustedOrigins: [requiredEnvVar("BETTER_AUTH_URL")], onAPIError: { throw: true, // This will help surface errors during development onError: async (error: unknown, ctx: AuthContext) => { const errorContext = { error, baseURL: ctx.baseURL, session: ctx.session, trustedOrigins: ctx.trustedOrigins, request: { url: ctx.options.baseURL, method: ctx.options.basePath, }, } console.log("Auth API error", errorContext) await logError("Auth API error", errorContext) }, }, user: { modelName: "UserTable", additionalFields: { subscriptionStatus: { type: "string", required: false, input: false }, subscriptionPlanId: { type: "string", required: false, input: false }, }, }, account: { modelName: "AccountTable", accountLinking: { enabled: true }, }, session: { modelName: "SessionTable", }, verification: { modelName: "VerificationTokenTable", }, emailAndPassword: { enabled: true, requireEmailVerification: true, }, emailVerification: { sendVerificationEmail: async ({ user, url, token }, request) => { }, }, socialProviders: { google: { clientId: requiredEnvVar("GOOGLE_CLIENT_ID"), clientSecret: requiredEnvVar("GOOGLE_SECRET_ID"), }, }, }) ``` ### Additional context ### Additional Context - The error seems related to how Next.js App Router modifies the Request object - The issue appears during both the initial auth request and the OAuth callback - The temp workaround ensures a standard-compliant Request object is passed to better-auth ### Questions 1. Is this expected behavior with Next.js App Router? 2. Should better-auth handle Request object normalization internally? 3. Could this be documented in the better-auth docs for Next.js App Router users?
GiteaMirror added the lockedbug labels 2026-04-13 03:49:32 -05:00
Author
Owner

@thehamsti commented on GitHub (Mar 5, 2025):

I am also running into this issue.

I don't have any custom configurations so this is the route that i ended up with.

import { toNextJsHandler } from "better-auth/next-js";
import { auth } from "@/lib/auth";
import { headers } from 'next/headers';

// Reconstruct request to fix 'n.get is not a function' error
const reconstructRequest = async (request: Request) => {
  const headersList = await headers();

  return new Request(request.url, {
    method: request.method,
    headers: headersList,
    body: request.body,
    duplex: 'half'
  } as RequestInit);
};

const handler = toNextJsHandler(auth);

export async function POST(request: Request) {  
  const modifiedRequest = await reconstructRequest(request);
  return handler.POST(modifiedRequest);
}

export async function GET(request: Request) {
  const modifiedRequest = await reconstructRequest(request);
  return handler.GET(modifiedRequest);
}
<!-- gh-comment-id:2699937694 --> @thehamsti commented on GitHub (Mar 5, 2025): I am also running into this issue. I don't have any custom configurations so this is the route that i ended up with. ```typescript import { toNextJsHandler } from "better-auth/next-js"; import { auth } from "@/lib/auth"; import { headers } from 'next/headers'; // Reconstruct request to fix 'n.get is not a function' error const reconstructRequest = async (request: Request) => { const headersList = await headers(); return new Request(request.url, { method: request.method, headers: headersList, body: request.body, duplex: 'half' } as RequestInit); }; const handler = toNextJsHandler(auth); export async function POST(request: Request) { const modifiedRequest = await reconstructRequest(request); return handler.POST(modifiedRequest); } export async function GET(request: Request) { const modifiedRequest = await reconstructRequest(request); return handler.GET(modifiedRequest); } ```
Author
Owner

@cmhand commented on GitHub (Mar 20, 2025):

Also running into this issue.

<!-- gh-comment-id:2741034772 --> @cmhand commented on GitHub (Mar 20, 2025): Also running into this issue.
Author
Owner

@jasonallen commented on GitHub (Mar 24, 2025):

Just ran into this too, but in my case it was i.get (vs n.get).

<!-- gh-comment-id:2746935063 --> @jasonallen commented on GitHub (Mar 24, 2025): Just ran into this too, but in my case it was `i.get` (vs `n.get`).
Author
Owner

@cmhand commented on GitHub (Mar 24, 2025):

@thehamsti workaround worked for me.

<!-- gh-comment-id:2748306463 --> @cmhand commented on GitHub (Mar 24, 2025): @thehamsti workaround worked for me.
Author
Owner

@roacfe commented on GitHub (Apr 2, 2025):

Same issue for me.
Could it be related to this? https://github.com/vercel/next.js/issues/60687

<!-- gh-comment-id:2773928834 --> @roacfe commented on GitHub (Apr 2, 2025): Same issue for me. Could it be related to this? https://github.com/vercel/next.js/issues/60687
Author
Owner

@Kinfe123 commented on GitHub (Apr 12, 2025):

this is mainly from next and you still can reconstruct those as you as mentioned @thehamsti. so feel free to do that.

<!-- gh-comment-id:2798769712 --> @Kinfe123 commented on GitHub (Apr 12, 2025): this is mainly from next and you still can reconstruct those as you as mentioned @thehamsti. so feel free to do that.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#8669