When generateId is false and using MySQL, social signin fails #697

Closed
opened 2026-03-13 08:00:42 -05:00 by GiteaMirror · 8 comments
Owner

Originally created by @soylomass on GitHub (Feb 17, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Install better-auth
  2. Set advanced -> generateId to false
  3. Setup database to use MySQL
  4. Try to signin using Google

Current vs. Expected behavior

The error "TypeError: Cannot read properties of undefined (reading 'field')" occurs in the withReturning function of the Kysely adapter. This happens specifically when useDatabaseGeneratedId is true during a create operation. The code tries to access where[0].field, but where is an empty array ([]) in the create context when database generates the id, causing the error.

Relevant Code:


    async withReturning(values, builder, model, where) {
      let res;
      if (config?.type === "mysql") {
        await builder.execute();
        **const field = values.id ? "id" : where[0].field ? where[0].field : "id"; // ERROR HERE when where = []**
        const value = values[field] || where[0].value;
        res = await db.selectFrom(getModelName(model)).selectAll().where(getField(model, field), "=", value).executeTakeFirst();
        return res;
      }
      if (config?.type === "mssql") {
        res = await builder.outputAll("inserted").executeTakeFirst();
        return res;
      }
      res = await builder.returningAll().executeTakeFirst();
      return res;
    },
    async create(data) {
      const { model, data: values, select } = data;
      const transformed = transformInput(values, model, "create");
      const builder = db.insertInto(getModelName(model)).values(transformed);
      return transformOutput(
        await withReturning(transformed, builder, model, **[]**), // where is [] here
        model,
        select
      );
    },

After inserting, withReturning tries to get the inserted row by searching by the id field, but there is no id field when using generateId = false.

What version of Better Auth are you using?

1.1.18

Provide environment information

- OS: Windows

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

Backend

Auth config (if applicable)

export const auth = betterAuth({
  socialProviders: {
    google: {
      clientId:
        'xxx',
      clientSecret: 'xxx',
    },
  },
  database: createPool({
    host: ormconfig.host,
    user: ormconfig.username,
    password: ormconfig.password,
    database: ormconfig.database,
  }),
  advanced: {
    generateId: false,
  },
});

Additional context

No response

Originally created by @soylomass on GitHub (Feb 17, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Install better-auth 2. Set advanced -> generateId to false 3. Setup database to use MySQL 4. Try to signin using Google ### Current vs. Expected behavior The error "TypeError: Cannot read properties of undefined (reading 'field')" occurs in the withReturning function of the Kysely adapter. This happens specifically when useDatabaseGeneratedId is true during a create operation. The code tries to access where[0].field, but where is an empty array ([]) in the create context when database generates the id, causing the error. Relevant Code: ``` async withReturning(values, builder, model, where) { let res; if (config?.type === "mysql") { await builder.execute(); **const field = values.id ? "id" : where[0].field ? where[0].field : "id"; // ERROR HERE when where = []** const value = values[field] || where[0].value; res = await db.selectFrom(getModelName(model)).selectAll().where(getField(model, field), "=", value).executeTakeFirst(); return res; } if (config?.type === "mssql") { res = await builder.outputAll("inserted").executeTakeFirst(); return res; } res = await builder.returningAll().executeTakeFirst(); return res; }, ``` ``` async create(data) { const { model, data: values, select } = data; const transformed = transformInput(values, model, "create"); const builder = db.insertInto(getModelName(model)).values(transformed); return transformOutput( await withReturning(transformed, builder, model, **[]**), // where is [] here model, select ); }, ``` After inserting, withReturning tries to get the inserted row by searching by the id field, but there is no id field when using generateId = false. ### What version of Better Auth are you using? 1.1.18 ### Provide environment information ```bash - OS: Windows ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript export const auth = betterAuth({ socialProviders: { google: { clientId: 'xxx', clientSecret: 'xxx', }, }, database: createPool({ host: ormconfig.host, user: ormconfig.username, password: ormconfig.password, database: ormconfig.database, }), advanced: { generateId: false, }, }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 08:00:42 -05:00
Author
Owner

@soylomass commented on GitHub (Feb 17, 2025):

Without digging too much into how everything works, I solved it by changing:

        await builder.execute();
        const field = values.id ? "id" : where[0].field ? where[0].field : "id";
        const value = values[field] || where[0].value;

With:

        const ret = await builder.execute();
        let value, field;
        if (ret[0] && ret[0].insertId) {
          value = ret[0].insertId;
          field = "id";
        } else {
          field = values.id ? "id" : where[0].field ? where[0].field : "id";
          value = values[field] || where[0].value;
        }
@soylomass commented on GitHub (Feb 17, 2025): Without digging too much into how everything works, I solved it by changing: ``` await builder.execute(); const field = values.id ? "id" : where[0].field ? where[0].field : "id"; const value = values[field] || where[0].value; ``` With: ``` const ret = await builder.execute(); let value, field; if (ret[0] && ret[0].insertId) { value = ret[0].insertId; field = "id"; } else { field = values.id ? "id" : where[0].field ? where[0].field : "id"; value = values[field] || where[0].value; } ```
Author
Owner

@CrutchTheClutch commented on GitHub (Mar 14, 2025):

I wasn't able to get this patch working on my end, but there is 100% some kind of issue here. My config works perfectly normal if I have generateId: true. As soon as I change it to false I start getting errors:

# SERVER_ERROR: [TypeError: Cannot read properties of undefined (reading 'value')]

@CrutchTheClutch commented on GitHub (Mar 14, 2025): I wasn't able to get this patch working on my end, but there is 100% some kind of issue here. My config works perfectly normal if I have `generateId: true`. As soon as I change it to `false` I start getting errors: `# SERVER_ERROR: [TypeError: Cannot read properties of undefined (reading 'value')]`
Author
Owner

@CrutchTheClutch commented on GitHub (Mar 16, 2025):

For anyone else running into this, you are able to pass a function to override the default ID generation. This is what I ended up doing in the meantime as a workaround:

  advanced: {
    generateId: ((options) => {
      return createID(options.model as keyof typeof prefixes);
    })
  },

Then I can use my custom function for how I want to generate ID's

import { ulid } from "ulid";

export const prefixes = {
  account: "acc",
  invitation: "inv",
  jwks: "jwk",
  member: "mbr",
  organization: "org",
  "rate-limit": "rtl",
  passkey: "psk",
  session: "ses",
  twoFactor: "2fa",
  user: "usr",
  verification: "ver",
} as const;

export function createID(prefix: keyof typeof prefixes): string {
  return [prefixes[prefix], ulid()].join("_");
}
@CrutchTheClutch commented on GitHub (Mar 16, 2025): For anyone else running into this, you are able to pass a function to override the default ID generation. This is what I ended up doing in the meantime as a workaround: ```ts advanced: { generateId: ((options) => { return createID(options.model as keyof typeof prefixes); }) }, ``` Then I can use my custom function for how I want to generate ID's ```ts import { ulid } from "ulid"; export const prefixes = { account: "acc", invitation: "inv", jwks: "jwk", member: "mbr", organization: "org", "rate-limit": "rtl", passkey: "psk", session: "ses", twoFactor: "2fa", user: "usr", verification: "ver", } as const; export function createID(prefix: keyof typeof prefixes): string { return [prefixes[prefix], ulid()].join("_"); } ```
Author
Owner

@soylomass commented on GitHub (Mar 16, 2025):

@CrutchTheClutch Nice. In my case, I use autogenerated IDs in the database, so generating an ID before inserting was not an option.

@soylomass commented on GitHub (Mar 16, 2025): @CrutchTheClutch Nice. In my case, I use autogenerated IDs in the database, so generating an ID before inserting was not an option.
Author
Owner

@focux commented on GitHub (Mar 21, 2025):

The issue is that MySQL doesn't support returning(), so the insert query won't return the inserted value with the auto-generated ids. Also, if your primary key is not an auto-incremented id, then @soylomass patch won't work because the insertId only works with auto-incremented primary keys/ids.

The fix is basically providing a generateId function to better-auth config, as @CrutchTheClutch did.

@focux commented on GitHub (Mar 21, 2025): The issue is that MySQL doesn't support `returning()`, so the insert query won't return the inserted value with the auto-generated ids. Also, if your primary key is not an auto-incremented id, then @soylomass patch won't work because the `insertId` only works with auto-incremented primary keys/ids. The fix is basically providing a `generateId` function to better-auth config, as @CrutchTheClutch did.
Author
Owner

@Bekacru commented on GitHub (Jun 16, 2025):

This should be fixed on latest. Feel free to tag me if you're still experiencing this issue.

@Bekacru commented on GitHub (Jun 16, 2025): This should be fixed on latest. Feel free to tag me if you're still experiencing this issue.
Author
Owner

@nestorzamili commented on GitHub (Jun 18, 2025):

Hi @Bekacru I'm still experiencing the issue on v1.2.9.

 ⨯ TypeError: Cannot read properties of undefined (reading 'fields')
    at m (.next/server/app/api/auth/[...all]/route.js:113:58819)
    at <unknown> (.next/server/app/api/auth/[...all]/route.js:113:63176)
    at Array.map (<anonymous>)
    at Object.findMany (.next/server/app/api/auth/[...all]/route.js:113:63157)
    at async Object.get (.next/server/app/api/auth/[...all]/route.js:112:14355)
    at async s9 (.next/server/app/api/auth/[...all]/route.js:112:14793)
    at async handler (.next/server/app/api/auth/[...all]/route.js:30:2917)
@nestorzamili commented on GitHub (Jun 18, 2025): Hi @Bekacru I'm still experiencing the issue on v1.2.9. ``` ⨯ TypeError: Cannot read properties of undefined (reading 'fields') at m (.next/server/app/api/auth/[...all]/route.js:113:58819) at <unknown> (.next/server/app/api/auth/[...all]/route.js:113:63176) at Array.map (<anonymous>) at Object.findMany (.next/server/app/api/auth/[...all]/route.js:113:63157) at async Object.get (.next/server/app/api/auth/[...all]/route.js:112:14355) at async s9 (.next/server/app/api/auth/[...all]/route.js:112:14793) at async handler (.next/server/app/api/auth/[...all]/route.js:30:2917) ```
Author
Owner

@nestorzamili commented on GitHub (Jun 19, 2025):

Hi @Bekacru I'm still experiencing the issue on v1.2.9.

 ⨯ TypeError: Cannot read properties of undefined (reading 'fields')
    at m (.next/server/app/api/auth/[...all]/route.js:113:58819)
    at <unknown> (.next/server/app/api/auth/[...all]/route.js:113:63176)
    at Array.map (<anonymous>)
    at Object.findMany (.next/server/app/api/auth/[...all]/route.js:113:63157)
    at async Object.get (.next/server/app/api/auth/[...all]/route.js:112:14355)
    at async s9 (.next/server/app/api/auth/[...all]/route.js:112:14793)
    at async handler (.next/server/app/api/auth/[...all]/route.js:30:2917)

Removing the database config from the rate limit solved the issue for me.

Before

  rateLimit: {
    enabled: true,
    storage: 'database',
    modelName: 'RateLimit',
    window: 5 * 60,
    max: 10,
  },

After

  rateLimit: {
    enabled: true,
    window: 5 * 60,
    max: 10,
  },
@nestorzamili commented on GitHub (Jun 19, 2025): > Hi [@Bekacru](https://github.com/Bekacru) I'm still experiencing the issue on v1.2.9. > > ``` > ⨯ TypeError: Cannot read properties of undefined (reading 'fields') > at m (.next/server/app/api/auth/[...all]/route.js:113:58819) > at <unknown> (.next/server/app/api/auth/[...all]/route.js:113:63176) > at Array.map (<anonymous>) > at Object.findMany (.next/server/app/api/auth/[...all]/route.js:113:63157) > at async Object.get (.next/server/app/api/auth/[...all]/route.js:112:14355) > at async s9 (.next/server/app/api/auth/[...all]/route.js:112:14793) > at async handler (.next/server/app/api/auth/[...all]/route.js:30:2917) > ``` Removing the database config from the rate limit solved the issue for me. Before ``` rateLimit: { enabled: true, storage: 'database', modelName: 'RateLimit', window: 5 * 60, max: 10, }, ``` After ``` rateLimit: { enabled: true, window: 5 * 60, max: 10, }, ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#697