Better Auth unable to query database #815

Closed
opened 2026-03-13 08:05:23 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @Abbhiishek on GitHub (Mar 9, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Migrating from next auth to better auth following the migration guide.

the errors logs:

2025-03-09T16:51:50.641Z ERROR [Better Auth]: Better auth was unable to query your database.
Error:  [error: syntax error at or near "="] {
  length: 91,
  severity: 'ERROR',
  code: '42601',
  detail: undefined,
  hint: undefined,
  position: '181',
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'scan.l',
  line: '1242',
  routine: 'scanner_yyerror'
}

GET /api/auth/error?error=internal_server_error 200 in 86ms

Current vs. Expected behavior

not able to sign in and signup with socials login

What version of Better Auth are you using?

1.2.3

Provide environment information

- OS Windows 11

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

Other

Auth config (if applicable)

here is my auth config


import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";
import { nextCookies } from "better-auth/next-js";
import { username } from "better-auth/plugins";
import { accounts, sessions, users, verifications } from "@/db/schema/user";

export const auth = betterAuth({
    emailAndPassword: {
        enabled: true
    },
    plugins: [
        nextCookies(),
        username()
    ],
    database: drizzleAdapter(db, {
        provider: "pg",
        schema: {
            user: users,
            account: accounts,
            session: sessions,
            verification: verifications
        },
    }),
    account: {
        accountLinking: {
            enabled: true,
            trustedProviders: ['github', 'google'],
        }
    },
    session: {
        fields: {
            expiresAt: "expires",
            token: "sessionToken"
        }
    },
    accounts: {
        fields: {
            accountId: "providerAccountId",
            refreshToken: "refresh_token",
            accessToken: "access_token",
            accessTokenExpiresAt: "access_token_expires",
            idToken: "id_token",
        }
    },
    socialProviders: {
        github: {
            clientId: process.env.AUTH_GITHUB_ID as string,
            clientSecret: process.env.AUTH_GITHUB_SECRET as string,
        },
        google: {
            clientId: process.env.AUTH_GOOGLE_ID as string,
            clientSecret: process.env.AUTH_GOOGLE_SECRET as string,
        },
    },
});

Additional context

No response

Originally created by @Abbhiishek on GitHub (Mar 9, 2025). ### Is this suited for github? - [ ] Yes, this is suited for github ### To Reproduce Migrating from next auth to better auth following the migration guide. the errors logs: ``` 2025-03-09T16:51:50.641Z ERROR [Better Auth]: Better auth was unable to query your database. Error: [error: syntax error at or near "="] { length: 91, severity: 'ERROR', code: '42601', detail: undefined, hint: undefined, position: '181', internalPosition: undefined, internalQuery: undefined, where: undefined, schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'scan.l', line: '1242', routine: 'scanner_yyerror' } ``` > GET /api/auth/error?error=internal_server_error 200 in 86ms ### Current vs. Expected behavior not able to sign in and signup with socials login ### What version of Better Auth are you using? 1.2.3 ### Provide environment information ```bash - OS Windows 11 ``` ### Which area(s) are affected? (Select all that apply) Other ### Auth config (if applicable) ```typescript here is my auth config import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { db } from "@/db"; import { nextCookies } from "better-auth/next-js"; import { username } from "better-auth/plugins"; import { accounts, sessions, users, verifications } from "@/db/schema/user"; export const auth = betterAuth({ emailAndPassword: { enabled: true }, plugins: [ nextCookies(), username() ], database: drizzleAdapter(db, { provider: "pg", schema: { user: users, account: accounts, session: sessions, verification: verifications }, }), account: { accountLinking: { enabled: true, trustedProviders: ['github', 'google'], } }, session: { fields: { expiresAt: "expires", token: "sessionToken" } }, accounts: { fields: { accountId: "providerAccountId", refreshToken: "refresh_token", accessToken: "access_token", accessTokenExpiresAt: "access_token_expires", idToken: "id_token", } }, socialProviders: { github: { clientId: process.env.AUTH_GITHUB_ID as string, clientSecret: process.env.AUTH_GITHUB_SECRET as string, }, google: { clientId: process.env.AUTH_GOOGLE_ID as string, clientSecret: process.env.AUTH_GOOGLE_SECRET as string, }, }, }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 08:05:23 -05:00
Author
Owner

@moshetanzer commented on GitHub (Mar 23, 2025):

Did you manage to resolve this?

@moshetanzer commented on GitHub (Mar 23, 2025): Did you manage to resolve this?
Author
Owner

@dantman commented on GitHub (Apr 11, 2025):

I ended up here from the same error message. Also Drizzle (though I refactored the schema to match better-auth's generated Drizzle one) and in the middle of setting up Google login.

 POST /api/auth/sign-in/social 200 in 664ms
2025-04-11T02:00:45.718Z ERROR [Better Auth]: Better auth was unable to query your database.
Error:  [error: syntax error at or near "="] {
  length: 91,
  severity: 'ERROR',
  code: '42601',
  detail: undefined,
  hint: undefined,
  position: '210',
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'scan.l',
  line: '1188',
  routine: 'scanner_yyerror'
}
 GET /api/auth/callback/google?state=

I haven't brute force troubleshooted yet, but even if we find the issue were having here IMHO this error that clearly comes from better auth knowing it's trying to make a DB query should provide some information on what the DB query actually is.

@dantman commented on GitHub (Apr 11, 2025): I ended up here from the same error message. Also Drizzle (though I refactored the schema to match better-auth's generated Drizzle one) and in the middle of setting up Google login. ``` POST /api/auth/sign-in/social 200 in 664ms 2025-04-11T02:00:45.718Z ERROR [Better Auth]: Better auth was unable to query your database. Error: [error: syntax error at or near "="] { length: 91, severity: 'ERROR', code: '42601', detail: undefined, hint: undefined, position: '210', internalPosition: undefined, internalQuery: undefined, where: undefined, schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'scan.l', line: '1188', routine: 'scanner_yyerror' } GET /api/auth/callback/google?state= ``` I haven't brute force troubleshooted yet, but even if we find the issue were having here IMHO this error that clearly comes from better auth knowing it's trying to make a DB query should provide some information on what the DB query actually is.
Author
Owner

@dantman commented on GitHub (Apr 11, 2025):

Here's what I've found:

  1. The error is coming from here which I presume means there's a database error when the Drizzle adapter is called through findOAuthUser.
    84194242ae/packages/better-auth/src/oauth2/link-account.ts (L21-L35)

  2. I ran Next.js in debug mode and put a breakpoint in node_modules/better-auth/dist/adapters/drizzle-adapter/index.mjs's findOne implementation, which should be here:
    84194242ae/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts (L297-L308)

  3. The error happened when findOne was being run on the "account" with a where of [{value: "<my google ID>", field: "accountId"}, {value: "google", field: "providerId"}]}

  4. When we reached here with model: "account" field: "accountId"
    84194242ae/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts (L35)
    I discovered that f.fieldName was "accountId" despite having this config:

	accounts: {
		fields: {
			accountId: "providerAccountId",
		},
	},
  1. On a hunch I changed that to this and it found the field correctly.
	account: {
		fields: {
			accountId: "providerAccountId",
		},
	},
  1. So the first issue is that docs/guides/next-auth-migration-guide#accounts-schema is incorrectly telling people to use accounts and betterAuth's options argument is loosely typed enough you don't notice that's not on the right key.

  2. Following this I ended up with this error:
    BetterAuthError: The field "id" does not exist in the schema for the model "account". Please update your schema. {name: 'BetterAuthError', cause: undefined, stack: '', message: 'The field "id" does not exist in the schema … model "account". Please update your schema.'}

  3. This is because next-auth has a primary key on (providerId, providerAccountId) while better-auth has an additional id column and does not use the type column. I had to do a multi step refactor including a custom one to populate the id.

-- Populate the account table's ID column with values from the previous primary key --
UPDATE "account" a
SET "id" = a."providerId" || '-' || a."providerAccountId"
WHERE a."id" IS NULL;
  1. Now I've moved on to errors like State Mismatch. Verification not found and error: invalid input syntax for type integer: "<date string>

I haven't finished fixing things yet, but at the very least we can say that the account table from next-auth/Auth.js does not map as cleanly to better-auth as the (docs/guides/next-auth-migration-guide)[https://www.better-auth.com/docs/guides/next-auth-migration-guide] documentation suggests.

@dantman commented on GitHub (Apr 11, 2025): Here's what I've found: 1. The error is coming from here which I presume means there's a database error when the Drizzle adapter is called through findOAuthUser. https://github.com/better-auth/better-auth/blob/84194242ae495b48d705a023f489ccb7fbfcbd81/packages/better-auth/src/oauth2/link-account.ts#L21-L35 2. I ran Next.js in debug mode and put a breakpoint in `node_modules/better-auth/dist/adapters/drizzle-adapter/index.mjs`'s findOne implementation, which should be here: https://github.com/better-auth/better-auth/blob/84194242ae495b48d705a023f489ccb7fbfcbd81/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts#L297-L308 3. The error happened when findOne was being run on the "account" with a where of `[{value: "<my google ID>", field: "accountId"}, {value: "google", field: "providerId"}]}` 4. When we reached here with `model: "account"` `field: "accountId"` https://github.com/better-auth/better-auth/blob/84194242ae495b48d705a023f489ccb7fbfcbd81/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts#L35 I discovered that `f.fieldName` was `"accountId"` despite having this config: ```ts accounts: { fields: { accountId: "providerAccountId", }, }, ``` 5. On a hunch I changed that to this and it found the field correctly. ```ts account: { fields: { accountId: "providerAccountId", }, }, ``` 6. So the first issue is that [docs/guides/next-auth-migration-guide#accounts-schema](https://www.better-auth.com/docs/guides/next-auth-migration-guide#accounts-schema) is incorrectly telling people to use `accounts` and betterAuth's options argument is loosely typed enough you don't notice that's not on the right key. 7. Following this I ended up with this error: `BetterAuthError: The field "id" does not exist in the schema for the model "account". Please update your schema. {name: 'BetterAuthError', cause: undefined, stack: '', message: 'The field "id" does not exist in the schema … model "account". Please update your schema.'}` 8. This is because next-auth has a primary key on `(providerId, providerAccountId)` while better-auth has an additional `id` column and does not use the `type` column. I had to do a multi step refactor including a custom one to populate the id. ```sql -- Populate the account table's ID column with values from the previous primary key -- UPDATE "account" a SET "id" = a."providerId" || '-' || a."providerAccountId" WHERE a."id" IS NULL; ``` 9. Now I've moved on to errors like `State Mismatch. Verification not found` and `error: invalid input syntax for type integer: "<date string>` I haven't finished fixing things yet, but at the very least we can say that the account table from next-auth/Auth.js does not map as cleanly to better-auth as the (docs/guides/next-auth-migration-guide)[https://www.better-auth.com/docs/guides/next-auth-migration-guide] documentation suggests.
Author
Owner

@Abbhiishek commented on GitHub (Apr 11, 2025):

hey @dantman @moshetanzer sorry for late follow-up!

I was kind of able to fix the issue. i guess the issue was with schema and particularly with some timestamps

Current schema

export const accounts = pgTable('account', {
  id: text('id').primaryKey(),
  userId: text('userId')
    .notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
  providerId: text('providerId').notNull(),
  accountId: text('accountId').notNull(),
  refreshToken: text('refreshToken'),
  accessToken: text('accessToken'),
  accessTokenExpiresAt: timestamp('access_token_expires_at'),
  refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
  scope: text('scope'),
  password: text('password'),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow(),
  idToken: text('idToken'),
});

Previous schema

export const accounts = pgTable("account", {
    userId: text("userId")
        .notNull()
        .references(() => users.id, { onDelete: "cascade" }),
    type: text("type").$type<AdapterAccountType>().notNull(),
    provider: text("provider").notNull(),
    providerAccountId: text("providerAccountId").notNull(),
    refresh_token: text("refresh_token"),
    access_token: text("access_token"),
    **expires_at: integer("expires_at"),  >>> this was renamed to accessTokenExpiresAt**
    token_type: text("token_type"),
    scope: text("scope"),
    id_token: text("id_token"),
    session_state: text("session_state"),
},
    (account) => ({
        compoundKey: primaryKey({
            columns: [account.provider, account.providerAccountId],
        }),
    })
)

i guess this migration flow caused the issue as the new renamed column had type of integer rather than timestamp although it was mentioned in schema it was overlooked maybe somehow or i prompted it to rename in terminal. PS. Learnt a lesson to always cross verify migration files feature doing migration

ALTER TABLE "account" RENAME COLUMN "accessTokenExpiresAt" TO "access_token_expires_at";  >>> **ISSUE** carried the same type as integer rather than timestamp
ALTER TABLE "account" DROP COLUMN IF EXISTS "access_token_expires_at"; >> had to drop it
ALTER TABLE "account" ADD COLUMN "access_token_expires_at" timestamp; >> add it again

so according to me somehow the accessTokenExpiresAt which had type of integer when renaming to access_token_expires_at actually renamed the field but didn't added it as timestamp type

@Abbhiishek commented on GitHub (Apr 11, 2025): hey @dantman @moshetanzer sorry for late follow-up! I was kind of able to fix the issue. i guess the issue was with schema and particularly with some timestamps ## Current schema ```ts export const accounts = pgTable('account', { id: text('id').primaryKey(), userId: text('userId') .notNull() .references(() => users.id, { onDelete: 'cascade' }), providerId: text('providerId').notNull(), accountId: text('accountId').notNull(), refreshToken: text('refreshToken'), accessToken: text('accessToken'), accessTokenExpiresAt: timestamp('access_token_expires_at'), refreshTokenExpiresAt: timestamp('refresh_token_expires_at'), scope: text('scope'), password: text('password'), createdAt: timestamp('created_at').defaultNow(), updatedAt: timestamp('updated_at').defaultNow(), idToken: text('idToken'), }); ``` ## Previous schema ```ts export const accounts = pgTable("account", { userId: text("userId") .notNull() .references(() => users.id, { onDelete: "cascade" }), type: text("type").$type<AdapterAccountType>().notNull(), provider: text("provider").notNull(), providerAccountId: text("providerAccountId").notNull(), refresh_token: text("refresh_token"), access_token: text("access_token"), **expires_at: integer("expires_at"), >>> this was renamed to accessTokenExpiresAt** token_type: text("token_type"), scope: text("scope"), id_token: text("id_token"), session_state: text("session_state"), }, (account) => ({ compoundKey: primaryKey({ columns: [account.provider, account.providerAccountId], }), }) ) ``` i guess this migration flow caused the issue as the new renamed column had type of integer rather than timestamp although it was mentioned in schema it was overlooked maybe somehow or i prompted it to rename in terminal. **PS. Learnt a lesson to always cross verify migration files feature doing migration** ```sql ALTER TABLE "account" RENAME COLUMN "accessTokenExpiresAt" TO "access_token_expires_at"; >>> **ISSUE** carried the same type as integer rather than timestamp ALTER TABLE "account" DROP COLUMN IF EXISTS "access_token_expires_at"; >> had to drop it ALTER TABLE "account" ADD COLUMN "access_token_expires_at" timestamp; >> add it again ``` > so according to me somehow the `accessTokenExpiresAt` which had type of integer when renaming to `access_token_expires_at` actually renamed the field but didn't added it as timestamp type
Author
Owner

@Abbhiishek commented on GitHub (Apr 11, 2025):

I would recommend to migrate database manually rather than add alias mentioned in docs.

@Abbhiishek commented on GitHub (Apr 11, 2025): I would recommend to migrate database manually rather than add alias mentioned in docs.
Author
Owner

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

thanks @Abbhiishek for figuring out the issue. docs are now updated to reflect account and also mentions to add created and updated at fields

@Bekacru commented on GitHub (Apr 12, 2025): thanks @Abbhiishek for figuring out the issue. docs are now updated to reflect `account` and also mentions to add created and updated at fields
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#815