[GH-ISSUE #8969] [Better Auth]: Failed to run background task: TypeError: Response body object should not be disturbed or locked #19879

Open
opened 2026-04-15 19:14:13 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @chuwong35122 on GitHub (Apr 5, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8969

Is this suited for github?

  • Yes, this is suited for github

Reproduction

So I'm trying to send verification email on my tanstack start app (on the client-side) using the authClient.sendVerificationEmail. In the network tab the response from http://localhost:3000/api/auth/send-verification-email is

{
    "status": true
}

This error occurs in the backend-side of Tanstack start.

ERROR [Better Auth]: Failed to run background task: TypeError: Response body object should not be disturbed or locked
    at extractBody (node:internal/deps/undici/undici:5574:17)
    at new Request (node:internal/deps/undici/undici:9809:48)
    at Request.get _request [as _request] (file:///Users/chuwong/Devs/together.chuwii.com/node_modules/srvx/dist/adapters/node.mjs:251:21)
    at Request.desc.value (file:///Users/chuwong/Devs/together.chuwii.com/node_modules/srvx/dist/_chunks/_url.mjs:23:16)
    at formatValue (node:internal/util/inspect:850:19)
    at inspect (node:internal/util/inspect:387:10)
    at formatWithOptionsInternal (node:internal/util/inspect:2366:40)
    at formatWithOptions (node:internal/util/inspect:2228:10)
    at console.value (node:internal/console/constructor:336:14)
    at console.log (node:internal/console/constructor:384:61)

Note that the verification table in my db is empty (no record added).

Here's my tanstack start and better-auth versions in package.json

"@tanstack/react-devtools": "^0.9.13",
"@tanstack/react-router": "^1.168.10",
"@tanstack/react-router-devtools": "^1.166.11",
"@tanstack/react-router-ssr-query": "^1.166.10",
"@tanstack/react-start": "^1.167.16",
"@tanstack/router-plugin": "^1.167.12",
"@tanstack/zod-adapter": "^1.166.2",
"better-auth": "^1.5.6",

Current vs. Expected behavior

An error ERROR [Better Auth]: Failed to run background task: TypeError: Response body object should not be disturbed or locked occurred instead of email verification being sent.

What version of Better Auth are you using?

1.5.6

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:31 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T8103",
    "release": "25.3.0",
    "cpuCount": 8,
    "cpuModel": "Apple M1",
    "totalMemory": "8.00 GB",
    "freeMemory": "0.13 GB"
  },
  "node": {
    "version": "v22.15.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.6.2"
  },
  "frameworks": [
    {
      "name": "react",
      "version": "^19.2.4"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.20.0"
    },
    {
      "name": "postgres",
      "version": "^3.4.8"
    },
    {
      "name": "drizzle",
      "version": "^0.45.1"
    },
    {
      "name": "@neondatabase/serverless",
      "version": "^1.0.2"
    }
  ],
  "betterAuth": {
    "version": "^1.5.6",
    "config": {
      "emailAndPassword": {
        "enabled": true,
        "requireEmailVerification": true,
        "password": {}
      },
      "emailVerification": {
        "sendOnSignUp": true,
        "sendOnSignIn": true,
        "autoSignInAfterVerification": true
      },
      "user": {
        "additionalFields": {
          "userMetadata": {
            "type": "json",
            "required": false,
            "input": false,
            "fieldName": "user_metadata"
          },
          "appMetadata": {
            "type": "json",
            "required": false,
            "input": false,
            "fieldName": "app_metadata"
          },
          "invitedAt": {
            "type": "date",
            "required": false,
            "input": false,
            "fieldName": "invited_at"
          },
          "lastSignInAt": {
            "type": "date",
            "required": false,
            "input": false,
            "fieldName": "last_sign_in_at"
          }
        }
      },
      "socialProviders": {
        "discord": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        },
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true,
          "trustedProviders": [
            "google",
            "discord",
            "email-password"
          ]
        }
      },
      "plugins": [
        {
          "name": "anonymous",
          "config": {
            "id": "anonymous",
            "endpoints": {},
            "hooks": {
              "after": [
                {}
              ]
            },
            "schema": {
              "user": {
                "fields": {
                  "isAnonymous": {
                    "type": "boolean",
                    "required": false,
                    "input": false,
                    "defaultValue": false
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "INVALID_EMAIL_FORMAT": {
                "code": "INVALID_EMAIL_FORMAT",
                "message": "Email was not generated in a valid format"
              },
              "FAILED_TO_CREATE_USER": {
                "code": "FAILED_TO_CREATE_USER",
                "message": "Failed to create user"
              },
              "COULD_NOT_CREATE_SESSION": {
                "code": "COULD_NOT_CREATE_SESSION",
                "message": "Could not create session"
              },
              "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY": {
                "code": "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY",
                "message": "Anonymous users cannot sign in again anonymously"
              },
              "FAILED_TO_DELETE_ANONYMOUS_USER": {
                "code": "FAILED_TO_DELETE_ANONYMOUS_USER",
                "message": "Failed to delete anonymous user"
              },
              "USER_IS_NOT_ANONYMOUS": {
                "code": "USER_IS_NOT_ANONYMOUS",
                "message": "User is not anonymous"
              },
              "DELETE_ANONYMOUS_USER_DISABLED": {
                "code": "DELETE_ANONYMOUS_USER_DISABLED",
                "message": "Deleting anonymous users is disabled"
              }
            }
          }
        },
        {
          "name": "tanstack-start-cookies",
          "config": {
            "id": "tanstack-start-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        },
        {
          "name": "jwt",
          "config": {
            "id": "jwt",
            "endpoints": {},
            "hooks": {
              "after": [
                {}
              ]
            },
            "schema": {
              "jwks": {
                "fields": {
                  "publicKey": {
                    "type": "string",
                    "required": true
                  },
                  "privateKey": {
                    "type": "string",
                    "required": true
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true
                  },
                  "expiresAt": {
                    "type": "date",
                    "required": false
                  }
                }
              }
            }
          }
        }
      ],
      "advanced": {
        "cookiePrefix": "xxx"
      }
    }
  }
}

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

Backend

Auth config (if applicable)

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'pg',
    schema: {
      user: userTable,
      session: sessionTable,
      account: accountTable,
      verification: verificationTable,
      jwks: jwtTable,
    },
  }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
    password: {
      hash: async (password) => {
        return await bcrypt.hash(password, 10)
      },
      verify: async ({ hash, password }) => {
        return await bcrypt.compare(password, hash)
      },
    },
  },
  emailVerification: {
    sendOnSignUp: true,
    sendOnSignIn: true,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url, token }, request) => {
      console.log('sendVerificationEmail')
      console.log(request)
      void sendEmail({
        data: {
          to: user.email,
          subject: 'Verify your email address',
          text: `Click the link to verify your email: ${url}`,
        },
      })
    },
  },
  user: {
    additionalFields: {
      userMetadata: {
        type: 'json',
        required: false,
        input: false,
        fieldName: 'user_metadata',
      },
      appMetadata: {
        type: 'json',
        required: false,
        input: false,
        fieldName: 'app_metadata',
      },
      invitedAt: {
        type: 'date',
        required: false,
        input: false,
        fieldName: 'invited_at',
      },
      lastSignInAt: {
        type: 'date',
        required: false,
        input: false,
        fieldName: 'last_sign_in_at',
      },
    },
  },
  socialProviders: {
    discord: {
      clientId: "xxx"
      clientSecret: "xxx"
    },
    google: {
      clientId: "xxx"
      clientSecret: "xxx"
    },
  },
  account: {
    accountLinking: {
      enabled: true,
      trustedProviders: ['google', 'discord', 'email-password'],
    },
  },
  plugins: [anonymous(), tanstackStartCookies(), jwt()],
  advanced: {
    cookiePrefix: "xxx",
  },
})

Additional context

No response

Originally created by @chuwong35122 on GitHub (Apr 5, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8969 ### Is this suited for github? - [ ] Yes, this is suited for github ### Reproduction So I'm trying to send verification email on my tanstack start app (on the client-side) using the authClient.sendVerificationEmail. In the network tab the response from `http://localhost:3000/api/auth/send-verification-email` is ``` { "status": true } ``` This error occurs in the backend-side of Tanstack start. ``` ERROR [Better Auth]: Failed to run background task: TypeError: Response body object should not be disturbed or locked at extractBody (node:internal/deps/undici/undici:5574:17) at new Request (node:internal/deps/undici/undici:9809:48) at Request.get _request [as _request] (file:///Users/chuwong/Devs/together.chuwii.com/node_modules/srvx/dist/adapters/node.mjs:251:21) at Request.desc.value (file:///Users/chuwong/Devs/together.chuwii.com/node_modules/srvx/dist/_chunks/_url.mjs:23:16) at formatValue (node:internal/util/inspect:850:19) at inspect (node:internal/util/inspect:387:10) at formatWithOptionsInternal (node:internal/util/inspect:2366:40) at formatWithOptions (node:internal/util/inspect:2228:10) at console.value (node:internal/console/constructor:336:14) at console.log (node:internal/console/constructor:384:61) ``` Note that the `verification` table in my db is empty (no record added). Here's my tanstack start and better-auth versions in package.json "@tanstack/react-devtools": "^0.9.13", "@tanstack/react-router": "^1.168.10", "@tanstack/react-router-devtools": "^1.166.11", "@tanstack/react-router-ssr-query": "^1.166.10", "@tanstack/react-start": "^1.167.16", "@tanstack/router-plugin": "^1.167.12", "@tanstack/zod-adapter": "^1.166.2", "better-auth": "^1.5.6", ### Current vs. Expected behavior An error `ERROR [Better Auth]: Failed to run background task: TypeError: Response body object should not be disturbed or locked` occurred instead of email verification being sent. ### What version of Better Auth are you using? 1.5.6 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:31 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T8103", "release": "25.3.0", "cpuCount": 8, "cpuModel": "Apple M1", "totalMemory": "8.00 GB", "freeMemory": "0.13 GB" }, "node": { "version": "v22.15.1", "env": "development" }, "packageManager": { "name": "npm", "version": "11.6.2" }, "frameworks": [ { "name": "react", "version": "^19.2.4" } ], "databases": [ { "name": "pg", "version": "^8.20.0" }, { "name": "postgres", "version": "^3.4.8" }, { "name": "drizzle", "version": "^0.45.1" }, { "name": "@neondatabase/serverless", "version": "^1.0.2" } ], "betterAuth": { "version": "^1.5.6", "config": { "emailAndPassword": { "enabled": true, "requireEmailVerification": true, "password": {} }, "emailVerification": { "sendOnSignUp": true, "sendOnSignIn": true, "autoSignInAfterVerification": true }, "user": { "additionalFields": { "userMetadata": { "type": "json", "required": false, "input": false, "fieldName": "user_metadata" }, "appMetadata": { "type": "json", "required": false, "input": false, "fieldName": "app_metadata" }, "invitedAt": { "type": "date", "required": false, "input": false, "fieldName": "invited_at" }, "lastSignInAt": { "type": "date", "required": false, "input": false, "fieldName": "last_sign_in_at" } } }, "socialProviders": { "discord": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" }, "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" } }, "account": { "accountLinking": { "enabled": true, "trustedProviders": [ "google", "discord", "email-password" ] } }, "plugins": [ { "name": "anonymous", "config": { "id": "anonymous", "endpoints": {}, "hooks": { "after": [ {} ] }, "schema": { "user": { "fields": { "isAnonymous": { "type": "boolean", "required": false, "input": false, "defaultValue": false } } } }, "$ERROR_CODES": { "INVALID_EMAIL_FORMAT": { "code": "INVALID_EMAIL_FORMAT", "message": "Email was not generated in a valid format" }, "FAILED_TO_CREATE_USER": { "code": "FAILED_TO_CREATE_USER", "message": "Failed to create user" }, "COULD_NOT_CREATE_SESSION": { "code": "COULD_NOT_CREATE_SESSION", "message": "Could not create session" }, "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY": { "code": "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY", "message": "Anonymous users cannot sign in again anonymously" }, "FAILED_TO_DELETE_ANONYMOUS_USER": { "code": "FAILED_TO_DELETE_ANONYMOUS_USER", "message": "Failed to delete anonymous user" }, "USER_IS_NOT_ANONYMOUS": { "code": "USER_IS_NOT_ANONYMOUS", "message": "User is not anonymous" }, "DELETE_ANONYMOUS_USER_DISABLED": { "code": "DELETE_ANONYMOUS_USER_DISABLED", "message": "Deleting anonymous users is disabled" } } } }, { "name": "tanstack-start-cookies", "config": { "id": "tanstack-start-cookies", "hooks": { "after": [ {} ] } } }, { "name": "jwt", "config": { "id": "jwt", "endpoints": {}, "hooks": { "after": [ {} ] }, "schema": { "jwks": { "fields": { "publicKey": { "type": "string", "required": true }, "privateKey": { "type": "string", "required": true }, "createdAt": { "type": "date", "required": true }, "expiresAt": { "type": "date", "required": false } } } } } } ], "advanced": { "cookiePrefix": "xxx" } } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg', schema: { user: userTable, session: sessionTable, account: accountTable, verification: verificationTable, jwks: jwtTable, }, }), emailAndPassword: { enabled: true, requireEmailVerification: true, password: { hash: async (password) => { return await bcrypt.hash(password, 10) }, verify: async ({ hash, password }) => { return await bcrypt.compare(password, hash) }, }, }, emailVerification: { sendOnSignUp: true, sendOnSignIn: true, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url, token }, request) => { console.log('sendVerificationEmail') console.log(request) void sendEmail({ data: { to: user.email, subject: 'Verify your email address', text: `Click the link to verify your email: ${url}`, }, }) }, }, user: { additionalFields: { userMetadata: { type: 'json', required: false, input: false, fieldName: 'user_metadata', }, appMetadata: { type: 'json', required: false, input: false, fieldName: 'app_metadata', }, invitedAt: { type: 'date', required: false, input: false, fieldName: 'invited_at', }, lastSignInAt: { type: 'date', required: false, input: false, fieldName: 'last_sign_in_at', }, }, }, socialProviders: { discord: { clientId: "xxx" clientSecret: "xxx" }, google: { clientId: "xxx" clientSecret: "xxx" }, }, account: { accountLinking: { enabled: true, trustedProviders: ['google', 'discord', 'email-password'], }, }, plugins: [anonymous(), tanstackStartCookies(), jwt()], advanced: { cookiePrefix: "xxx", }, }) ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-04-15 19:14:13 -05:00
Author
Owner

@FaryalRizwaan commented on GitHub (Apr 7, 2026):

Hi,

I’d like to take this on. I’ve traced the crash: Better Auth consumes the request body during auth, then passes the same ctx.request to the background email handler, triggering the locked body error. The fix is to swap ctx.request for ctx.request?.clone() in email-verification.ts so the callback receives a fresh, readable stream.
I’ve already forked the repo and started the changes.

Could I be assigned?
Thanks!

<!-- gh-comment-id:4198579364 --> @FaryalRizwaan commented on GitHub (Apr 7, 2026): Hi, I’d like to take this on. I’ve traced the crash: Better Auth consumes the request body during auth, then passes the same ctx.request to the background email handler, triggering the locked body error. The fix is to swap ctx.request for ctx.request?.clone() in email-verification.ts so the callback receives a fresh, readable stream. I’ve already forked the repo and started the changes. **Could I be assigned**? Thanks!
Author
Owner

@bytaesu commented on GitHub (Apr 8, 2026):

Hi,

I’d like to take this on. I’ve traced the crash: Better Auth consumes the request body during auth, then passes the same ctx.request to the background email handler, triggering the locked body error. The fix is to swap ctx.request for ctx.request?.clone() in email-verification.ts so the callback receives a fresh, readable stream. I’ve already forked the repo and started the changes.

Could I be assigned? Thanks!

@FaryalRizwaan Thanks for your interest in contributing!

If this isn't a new feature, you don't need to ask for approval. Feel free to proceed, and mention me if needed. (Same message from Discord 😁)

<!-- gh-comment-id:4208342595 --> @bytaesu commented on GitHub (Apr 8, 2026): > Hi, > > I’d like to take this on. I’ve traced the crash: Better Auth consumes the request body during auth, then passes the same ctx.request to the background email handler, triggering the locked body error. The fix is to swap ctx.request for ctx.request?.clone() in email-verification.ts so the callback receives a fresh, readable stream. I’ve already forked the repo and started the changes. > > **Could I be assigned**? Thanks! @FaryalRizwaan Thanks for your interest in contributing! If this isn't a new feature, you don't need to ask for approval. Feel free to proceed, and mention me if needed. (Same message from Discord 😁)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19879