[GH-ISSUE #6124] MongoDB adapter update function returns undefined fields causing INTERNAL_SERVER_ERROR on session update #27746

Closed
opened 2026-04-17 18:55:35 -05:00 by GiteaMirror · 12 comments
Owner

Originally created by @fromi on GitHub (Nov 20, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6124

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Use the mongoDB adapter with MongoDB 6.0.2 Community or MongoDB 4.0.3 Community.
Trigger a session refresh (1 day by default)
Result : INTERNAL_SERVER_ERROR TypeError: Cannot read properties of undefined (reading 'valueOf')

Current vs. Expected behavior

The mongoDB adapter update function return this session object:

session {
  expiresAt: undefined,
  token: undefined,
  createdAt: undefined,
  updatedAt: undefined,
  ipAddress: undefined,
  userAgent: undefined,
  userId: undefined,
  id: undefined
}

What version of Better Auth are you using?

1.3.34

System info

`npx @better-auth/cli info` does not work:

2025-11-20T08:51:00.095Z ERROR [Better Auth]: [#better-auth]: Couldn't read your auth config. TypeError: Cannot read properties of undefined (reading 'startsWith')
    at connectionStringHasValidScheme (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb-connection-string-url\lib\index.js:9:30)
    at new ConnectionString (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb-connection-string-url\lib\index.js:85:34)
    at parseOptions (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb\lib\connection_string.js:191:17)
    at new MongoClient (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb\lib\mongo_client.js:48:63)
    at C:/Users/romai/IdeaProjects/game-park/app/auth.ts:9:16
    at async Function.import (C:\Users\romai\AppData\Local\npm-cache\_npx\167ca1f116d365e6\node_modules\jiti\dist\jiti.cjs:1:158301)
    at async resolveConfig (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/c12/dist/index.mjs:320:20)
    at async loadConfig (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/c12/dist/index.mjs:149:22)
    at async getConfig (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:1990:30)
    at async getBetterAuthInfo (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:3313:22)

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

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  database: mongodbAdapter(client.db(), { client, usePlural: true, debugLogs: { update: true } })
});

Additional context

No response

Originally created by @fromi on GitHub (Nov 20, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6124 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Use the mongoDB adapter with MongoDB 6.0.2 Community or MongoDB 4.0.3 Community. Trigger a session refresh (1 day by default) Result : `INTERNAL_SERVER_ERROR TypeError: Cannot read properties of undefined (reading 'valueOf')` ### Current vs. Expected behavior The mongoDB adapter update function return this session object: ``` session { expiresAt: undefined, token: undefined, createdAt: undefined, updatedAt: undefined, ipAddress: undefined, userAgent: undefined, userId: undefined, id: undefined } ``` ### What version of Better Auth are you using? 1.3.34 ### System info ```bash `npx @better-auth/cli info` does not work: 2025-11-20T08:51:00.095Z ERROR [Better Auth]: [#better-auth]: Couldn't read your auth config. TypeError: Cannot read properties of undefined (reading 'startsWith') at connectionStringHasValidScheme (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb-connection-string-url\lib\index.js:9:30) at new ConnectionString (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb-connection-string-url\lib\index.js:85:34) at parseOptions (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb\lib\connection_string.js:191:17) at new MongoClient (C:\Users\romai\IdeaProjects\game-park\node_modules\mongodb\lib\mongo_client.js:48:63) at C:/Users/romai/IdeaProjects/game-park/app/auth.ts:9:16 at async Function.import (C:\Users\romai\AppData\Local\npm-cache\_npx\167ca1f116d365e6\node_modules\jiti\dist\jiti.cjs:1:158301) at async resolveConfig (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/c12/dist/index.mjs:320:20) at async loadConfig (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/c12/dist/index.mjs:149:22) at async getConfig (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:1990:30) at async getBetterAuthInfo (file:///C:/Users/romai/AppData/Local/npm-cache/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:3313:22) ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ database: mongodbAdapter(client.db(), { client, usePlural: true, debugLogs: { update: true } }) }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-17 18:55:35 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Nov 20, 2025):

[tag @better-auth-agent if you would like an answer from the Agent]

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3556663949 --> @better-auth-agent[bot] commented on GitHub (Nov 20, 2025): [tag @better-auth-agent if you would like an answer from the Agent] <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@fromi commented on GitHub (Nov 20, 2025):

Here are the logs from the adapter (debugLogs: { update: true }) :

INFO [Better Auth]: [MongoDB Adapter] #488 [1/4] update (Unsafe Input): {
  model: 'sessions',
  data: {
    expiresAt: 2025-11-27T08:52:57.556Z,
    updatedAt: 2025-11-20T08:52:57.556Z
  }
}
INFO [Better Auth]: [MongoDB Adapter] #488 [2/4] update (Parsed Input): {
  model: 'sessions',
  data: {
    expiresAt: 2025-11-27T08:52:57.556Z,
    updatedAt: 2025-11-20T08:52:57.556Z
  }
}
INFO [Better Auth]: [MongoDB Adapter] #488 [3/4] update (DB Result): {
  model: 'sessions',
  data: {
    lastErrorObject: { n: 1, updatedExisting: true },
    value: {
      _id: new ObjectId("691c8239ec95a82cdee3ab82"),
      expiresAt: 2025-11-27T08:52:57.556Z,
      token: 'ZU4bfHL9GNe9vhEJ7BjIGHNe4bS32sCJ',
      createdAt: 2025-11-18T14:27:05.424Z,
      updatedAt: 2025-11-20T08:52:57.556Z,
      ipAddress: '93.1.105.184',
      userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36',
      userId: new ObjectId("6880b0a1ae64e990bb1c459d")
    },
    ok: 1
  }
}
INFO [Better Auth]: [MongoDB Adapter] #488 [4/4] update (Parsed Result): {
  model: 'sessions',
  data: {
    expiresAt: undefined,
    token: undefined,
    createdAt: undefined,
    updatedAt: undefined,
    ipAddress: undefined,
    userAgent: undefined,
    userId: undefined,
    id: undefined
  }
}
<!-- gh-comment-id:3556684919 --> @fromi commented on GitHub (Nov 20, 2025): Here are the logs from the adapter (debugLogs: { update: true }) : ``` INFO [Better Auth]: [MongoDB Adapter] #488 [1/4] update (Unsafe Input): { model: 'sessions', data: { expiresAt: 2025-11-27T08:52:57.556Z, updatedAt: 2025-11-20T08:52:57.556Z } } INFO [Better Auth]: [MongoDB Adapter] #488 [2/4] update (Parsed Input): { model: 'sessions', data: { expiresAt: 2025-11-27T08:52:57.556Z, updatedAt: 2025-11-20T08:52:57.556Z } } INFO [Better Auth]: [MongoDB Adapter] #488 [3/4] update (DB Result): { model: 'sessions', data: { lastErrorObject: { n: 1, updatedExisting: true }, value: { _id: new ObjectId("691c8239ec95a82cdee3ab82"), expiresAt: 2025-11-27T08:52:57.556Z, token: 'ZU4bfHL9GNe9vhEJ7BjIGHNe4bS32sCJ', createdAt: 2025-11-18T14:27:05.424Z, updatedAt: 2025-11-20T08:52:57.556Z, ipAddress: '93.1.105.184', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36', userId: new ObjectId("6880b0a1ae64e990bb1c459d") }, ok: 1 } } INFO [Better Auth]: [MongoDB Adapter] #488 [4/4] update (Parsed Result): { model: 'sessions', data: { expiresAt: undefined, token: undefined, createdAt: undefined, updatedAt: undefined, ipAddress: undefined, userAgent: undefined, userId: undefined, id: undefined } } ```
Author
Owner

@dosubot[bot] commented on GitHub (Nov 20, 2025):

Hi @fromi! I'm Dosu and I’m helping the better-auth team.

This is a known issue with the MongoDB adapter: the update function returns the entire result object from findOneAndUpdate instead of just the updated document, which leads to all session fields being undefined and causes the INTERNAL_SERVER_ERROR you’re seeing. The fix is to update the adapter’s update method to check for a value property on the result and return res.value if it exists, otherwise return res directly. Here’s a patch you can apply:

async update(data) {
  const { model, where, update: values } = data;
  const clause = transform.convertWhereClause(where, model);
  const transformedData = transform.transformInput(values, model, "update");
  const res = await db.collection(transform.getModelName(model)).findOneAndUpdate(
    clause,
    { $set: transformedData },
    { returnDocument: "after" }
  );
  if (!res) return null;
  return transform.transformOutput(res?.value ? res.value : res, model);
}

This ensures the adapter always returns the updated document, not the wrapper object, preventing undefined fields in the session object and fixing the error [source].

Also, double-check that your config disables internal ID generation (advanced.database.generateId: false) and that your session schema uses valid MongoDB ObjectIds for IDs to avoid related issues [source].

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3556693377 --> @dosubot[bot] commented on GitHub (Nov 20, 2025): <!-- Greeting --> Hi @fromi! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known issue with the MongoDB adapter: the update function returns the entire result object from `findOneAndUpdate` instead of just the updated document, which leads to all session fields being undefined and causes the INTERNAL_SERVER_ERROR you’re seeing. The fix is to update the adapter’s update method to check for a `value` property on the result and return `res.value` if it exists, otherwise return `res` directly. Here’s a patch you can apply: ```js async update(data) { const { model, where, update: values } = data; const clause = transform.convertWhereClause(where, model); const transformedData = transform.transformInput(values, model, "update"); const res = await db.collection(transform.getModelName(model)).findOneAndUpdate( clause, { $set: transformedData }, { returnDocument: "after" } ); if (!res) return null; return transform.transformOutput(res?.value ? res.value : res, model); } ``` This ensures the adapter always returns the updated document, not the wrapper object, preventing undefined fields in the session object and fixing the error [[source]](https://github.com/better-auth/better-auth/issues/2508). Also, double-check that your config disables internal ID generation (`advanced.database.generateId: false`) and that your session schema uses valid MongoDB ObjectIds for IDs to avoid related issues [[source]](https://github.com/better-auth/better-auth/issues/5756). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/3a73fd1b-0e9b-4c0a-a92c-16f1a6e49a3f?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6124)
Author
Owner

@Paola3stefania commented on GitHub (Nov 20, 2025):

@fromi Hi ! Did you tried Dosu's patch? Its working now?

<!-- gh-comment-id:3558628727 --> @Paola3stefania commented on GitHub (Nov 20, 2025): @fromi Hi ! Did you tried Dosu's patch? Its working now?
Author
Owner

@fromi commented on GitHub (Nov 20, 2025):

Hi @Paola3stefania ! No, the patch makes no sense to me. "transform" does not exists on branch canary.
It looks like it exists on this branch though: fix/mongodb-user-id-issue. The bot might have picked some code from there.
Maybe this branch will fix my issue, but I could not even find if there is a pull request to integrate it.
Right now I tried to workaround the issue this way:

export async function getSession() {
  const headersList = await headers()
  try {
    return auth.api.getSession({ headers: headersList })
  } catch (e) {
    console.log('Error getting session, retry:', e)
    return auth.api.getSession({ headers: headersList })
  }
}

but without success.

<!-- gh-comment-id:3558779397 --> @fromi commented on GitHub (Nov 20, 2025): Hi @Paola3stefania ! No, the patch makes no sense to me. "transform" does not exists on branch canary. It looks like it exists on this branch though: `fix/mongodb-user-id-issue`. The bot might have picked some code from there. Maybe this branch will fix my issue, but I could not even find if there is a pull request to integrate it. Right now I tried to workaround the issue this way: ``` export async function getSession() { const headersList = await headers() try { return auth.api.getSession({ headers: headersList }) } catch (e) { console.log('Error getting session, retry:', e) return auth.api.getSession({ headers: headersList }) } } ``` but without success.
Author
Owner

@Paola3stefania commented on GitHub (Nov 20, 2025):

Looking deeper, this branch (fix(adapters)/mongodb-id-issue, merged as #5686) only changes ID serialization and where filters in the Mongo adapter – it doesn’t introduce any transform.* helpers. That transform layer exists in other adapters (Prisma/Drizzle) and probably in an earlier version of this branch, but it’s not part of the current MongoDB adapter on canary, which is why the bot’s patch doesn’t apply.

The actual fix for this needs to happen in the MongoDB adapter’s update implementation.

Right now the adapter is effectively passing the raw findOneAndUpdate result wrapper into the mapping layer. In the Node MongoDB driver that wrapper looks like { ok, lastErrorObject, value }, so when Better Auth tries to map it as a Session it can’t find token, expiresAt, etc. — everything ends up undefined, which explains both the broken session object and the valueOf error during refresh.

A minimal, non-breaking bugfix is to unwrap the value property and only map that:

const result = await collection.findOneAndUpdate(
  filter,
  updateDoc,
  { returnDocument: "after" }
)

const doc = (result as any)?.value ?? null
if (!doc) return null

return  doc  ;

This keeps the adapter’s public contract intact (“return the updated model or null”) and only fixes the internal implementation detail that was leaking the Mongo driver’s wrapper. It makes the session update path behave correctly instead of returning a model full of undefined fields.

I’m happy to help validate this with Mongo 4.0.x and 6.0.x once the change lands on canary.

<!-- gh-comment-id:3559176323 --> @Paola3stefania commented on GitHub (Nov 20, 2025): Looking deeper, this branch (fix(adapters)/mongodb-id-issue, merged as #5686) only changes ID serialization and where filters in the Mongo adapter – it doesn’t introduce any transform.* helpers. That transform layer exists in other adapters (Prisma/Drizzle) and probably in an earlier version of this branch, but it’s not part of the current MongoDB adapter on canary, which is why the bot’s patch doesn’t apply. ⸻ The actual fix for this needs to happen in the MongoDB adapter’s update implementation. Right now the adapter is effectively passing the raw findOneAndUpdate result wrapper into the mapping layer. In the Node MongoDB driver that wrapper looks like { ok, lastErrorObject, value }, so when Better Auth tries to map it as a Session it can’t find token, expiresAt, etc. — everything ends up undefined, which explains both the broken session object and the valueOf error during refresh. A minimal, non-breaking bugfix is to unwrap the value property and only map that: ``` const result = await collection.findOneAndUpdate( filter, updateDoc, { returnDocument: "after" } ) const doc = (result as any)?.value ?? null if (!doc) return null return doc ; ``` This keeps the adapter’s public contract intact (“return the updated model or null”) and only fixes the internal implementation detail that was leaking the Mongo driver’s wrapper. It makes the session update path behave correctly instead of returning a model full of undefined fields. I’m happy to help validate this with Mongo 4.0.x and 6.0.x once the change lands on canary.
Author
Owner

@fromi commented on GitHub (Nov 20, 2025):

Ok... I cannot find mapMongoDocToModel anywhere in the code for now:
https://github.com/search?q=repo%3Abetter-auth%2Fbetter-auth%20mapMongoDocToModel&type=code
I must not be looking where I should :/

Right now I created a workaround in my configuration that seems to be working:

database: (options: BetterAuthOptions) => {
    const originalAdapter = mongodbAdapter(client.db(), { client, usePlural: true, debugLogs: { update: true } })(options)
    return {
      ...originalAdapter,
      // workaround for https://github.com/better-auth/better-auth/issues/6124
      async update(data: any) {
        await originalAdapter.update(data)
        return originalAdapter.findOne(data)
      }
    }
  }

It makes an extra call to the db but it will be good enough before a fix is release :)
Thanks for investigating!

<!-- gh-comment-id:3559325800 --> @fromi commented on GitHub (Nov 20, 2025): Ok... I cannot find `mapMongoDocToModel` anywhere in the code for now: https://github.com/search?q=repo%3Abetter-auth%2Fbetter-auth%20mapMongoDocToModel&type=code I must not be looking where I should :/ Right now I created a workaround in my configuration that seems to be working: ``` database: (options: BetterAuthOptions) => { const originalAdapter = mongodbAdapter(client.db(), { client, usePlural: true, debugLogs: { update: true } })(options) return { ...originalAdapter, // workaround for https://github.com/better-auth/better-auth/issues/6124 async update(data: any) { await originalAdapter.update(data) return originalAdapter.findOne(data) } } } ``` It makes an extra call to the db but it will be good enough before a fix is release :) Thanks for investigating!
Author
Owner

@Paola3stefania commented on GitHub (Nov 20, 2025):

@fromi that would be part of the fix . Sorry if I didnt explain my self 100% correctly. Will put the PR up here, keepping you posted

<!-- gh-comment-id:3559346744 --> @Paola3stefania commented on GitHub (Nov 20, 2025): @fromi that would be part of the fix . Sorry if I didnt explain my self 100% correctly. Will put the PR up here, keepping you posted
Author
Owner

@ping-maxwell commented on GitHub (Nov 20, 2025):

Hello @fromi for now you can use mongodb version 6.8 or under, and better-auth will work.

<!-- gh-comment-id:3560594434 --> @ping-maxwell commented on GitHub (Nov 20, 2025): Hello @fromi for now you can use mongodb version 6.8 or under, and better-auth will work.
Author
Owner

@fromi commented on GitHub (Nov 21, 2025):

Hi @ping-maxwell , I use "mongodb": "^5.9.2" and it does not work.
I will try to upgrade to mongodb version ~6.8
I am stuck to version 6.16 or under because my production database is MongoDB 4.0.3 Community (which has reach end of life, however further version are under licence which prevents my current PASS provider from offering them).

<!-- gh-comment-id:3561430085 --> @fromi commented on GitHub (Nov 21, 2025): Hi @ping-maxwell , I use "mongodb": "^5.9.2" and it does not work. I will try to upgrade to mongodb version ~6.8 I am stuck to version 6.16 or under because my production database is MongoDB 4.0.3 Community (which has reach end of life, however further version are under licence which prevents my current PASS provider from offering them).
Author
Owner

@fromi commented on GitHub (Nov 21, 2025):

Hi @ping-maxwell, I tested with version 6.8 and version 6.16, both work just fine. The current adapter probably works for mongodb driver >6.0

<!-- gh-comment-id:3561618912 --> @fromi commented on GitHub (Nov 21, 2025): Hi @ping-maxwell, I tested with version 6.8 and version 6.16, both work just fine. The current adapter probably works for mongodb driver >6.0
Author
Owner

@ping-maxwell commented on GitHub (Nov 21, 2025):

Hi @ping-maxwell, I tested with version 6.8 and version 6.16, both work just fine. The current adapter probably works for mongodb driver >6.0

yeah

<!-- gh-comment-id:3564686246 --> @ping-maxwell commented on GitHub (Nov 21, 2025): > Hi [@ping-maxwell](https://github.com/ping-maxwell), I tested with version 6.8 and version 6.16, both work just fine. The current adapter probably works for mongodb driver >6.0 yeah
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27746