[GH-ISSUE #6200] 1.4 experimental join : The model "XXX" was not found in the query object #27765

Closed
opened 2026-04-17 18:57:41 -05:00 by GiteaMirror · 34 comments
Owner

Originally created by @bmichotte on GitHub (Nov 22, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6200

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I have the following setup :

// src/db/index.ts
export {
    accountRelations,
    accountsTable,
    sessionRelations,
    sessionsTable,
    subscriptionsTable,
    userRelations,
    userRoles,
    usersTable,
    verificationsTable,
} from './auth'
// src/db/auth.ts
export const usersTable = pgTable('users', {
 // ...
})

// so on, all tables are named with the following pattern : namesTable = pgTable('names')
export const auth = betterAuth({
    database: drizzleAdapter(db, {
        provider: 'pg',
        usePlural: true,
        schema: {
            users: schema.usersTable,
            sessions: schema.sessionsTable,
            accounts: schema.accountsTable,
            verifications: schema.verificationsTable,
            subscriptions: schema.subscriptionsTable,
        },
    }),
 })

This configuration works.

Current vs. Expected behavior

If I add

     experimental: {
         joins: true,
     },

on my better auth config, I got the following

2025-11-22T11:45:45.113Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "sessions" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate".
2025-11-22T11:45:45.113Z INFO [Better Auth]: Falling back to regular query

What version of Better Auth are you using?

1.4.0

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:55 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6031",
    "release": "24.6.0",
    "cpuCount": 16,
    "cpuModel": "Apple M3 Max",
    "totalMemory": "128.00 GB",
    "freeMemory": "7.19 GB"
  },
  "node": {
    "version": "v22.16.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.2"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^16.0.3"
    },
    {
      "name": "react",
      "version": "^19.2.0"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.16.3"
    },
    {
      "name": "drizzle",
      "version": "^0.44.7"
    }
  ],
  "betterAuth": {
    "version": "^1.4.0",
    "config": {
      "experimental": {
        "joins": true
      },
      "trustedOrigins": [
        "http://localhost:3000",
        "jdc://"
      ],
      "emailAndPassword": {
        "enabled": true
      },
      "socialProviders": {
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        }
      },
      "plugins": [
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        },
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists.",
              "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.",
              "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself",
              "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users",
              "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users",
              "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users",
              "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]",
              "BANNED_USER": "You have been banned from this application",
              "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users",
              "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself",
              "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value"
            },
            "schema": {
              "user": {
                "fields": {
                  "role": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banned": {
                    "type": "boolean",
                    "defaultValue": false,
                    "required": false,
                    "input": false
                  },
                  "banReason": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banExpires": {
                    "type": "date",
                    "required": false,
                    "input": false
                  }
                }
              },
              "session": {
                "fields": {
                  "impersonatedBy": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            }
          }
        },
        {
          "name": "expo",
          "config": {
            "id": "expo",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {}
          }
        },
        {
          "name": "stripe",
          "config": {
            "id": "stripe",
            "endpoints": {},
            "schema": {
              "subscription": {
                "fields": {
                  "plan": {
                    "type": "string",
                    "required": true
                  },
                  "referenceId": {
                    "type": "string",
                    "required": true
                  },
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  },
                  "stripeSubscriptionId": {
                    "type": "string",
                    "required": false
                  },
                  "status": {
                    "type": "string",
                    "defaultValue": "incomplete"
                  },
                  "periodStart": {
                    "type": "date",
                    "required": false
                  },
                  "periodEnd": {
                    "type": "date",
                    "required": false
                  },
                  "trialStart": {
                    "type": "date",
                    "required": false
                  },
                  "trialEnd": {
                    "type": "date",
                    "required": false
                  },
                  "cancelAtPeriodEnd": {
                    "type": "boolean",
                    "required": false,
                    "defaultValue": false
                  },
                  "seats": {
                    "type": "number",
                    "required": false
                  }
                }
              },
              "user": {
                "fields": {
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "SUBSCRIPTION_NOT_FOUND": "Subscription not found",
              "SUBSCRIPTION_PLAN_NOT_FOUND": "Subscription plan not found",
              "ALREADY_SUBSCRIBED_PLAN": "You're already subscribed to this plan",
              "UNABLE_TO_CREATE_CUSTOMER": "Unable to create customer",
              "FAILED_TO_FETCH_PLANS": "Failed to fetch plans",
              "EMAIL_VERIFICATION_REQUIRED": "Email verification is required before you can subscribe to a plan",
              "SUBSCRIPTION_NOT_ACTIVE": "Subscription is not active",
              "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION": "Subscription is not scheduled for cancellation"
            }
          }
        }
      ],
      "user": {
        "additionalFields": {
          "firstname": {
            "type": "string",
            "required": true
          },
          "lastname": {
            "type": "string",
            "required": true
          },
          "role": {
            "type": "string",
            "required": false,
            "defaultValue": "user",
            "input": false
          },
          "country": {
            "type": "string",
            "required": false,
            "defaultValue": "BE"
          },
          "locale": {
            "type": "string",
            "required": false,
            "defaultValue": "fr"
          }
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true,
          "allowDifferentEmails": true,
          "trustedProviders": [
            "google",
            "email-password"
          ]
        }
      }
    }
  }
}

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

Backend

Auth config (if applicable)

const stripeClient = new Stripe(env.STRIPE_SECRET_KEY, {
    apiVersion: '2025-11-17.clover',
})

export const auth = betterAuth({
    experimental: {
        joins: true,
    },
    database: drizzleAdapter(db, {
        provider: 'pg',
        usePlural: true,
        schema: {
            users: schema.usersTable,
            sessions: schema.sessionsTable,
            accounts: schema.accountsTable,
            verifications: schema.verificationsTable,
            subscriptions: schema.subscriptionsTable,
            sessionRelations: schema.sessionRelations,
            userRelations: schema.userRelations,
            accountRelations: schema.accountRelations,
        },
    }),
    trustedOrigins: [env.BETTER_AUTH_URL, 'jdc://'],
    emailAndPassword: {
        enabled: true,
        sendResetPassword: async ({ user, url, token }, _request) => {
            console.log('sendResetPassword', user, url, token)
            if (url.includes('callbackURL=/invite')) {
                await sendInvitation(user as unknown as EmailUser, url)
            } else {
                await sendReset(user as unknown as EmailUser, url)
            }
        },
    },
    socialProviders: {
        google: {
            clientId: env.GOOGLE_CLIENT_ID,
            clientSecret: env.GOOGLE_CLIENT_SECRET,
            mapProfileToUser: profile => {
                console.log('Google profile:', profile)
                return {
                    firstname: profile.given_name,
                    lastname: profile.family_name,
                }
            },
        },
    },
    plugins: [
        nextCookies(),
        admin(),
        expo(),
        stripe({
            stripeClient,
            stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
            createCustomerOnSignUp: true,
            onEvent: async event => {
                console.log(`Stripe event received: ${event.type}`, { event })
            },
            subscription: {
                enabled: true,
                authorizeReference: async ({ user, session, referenceId, action }) => {
                    console.log({ user, session, referenceId, action })
                    return true
                },
                plans: plans.map(({ name, priceId, annualDiscountPriceId, freeTrial }) => ({
                    name,
                    priceId,
                    annualDiscountPriceId,
                    freeTrial: {
                        days: freeTrial,
                        onTrialStart: async subscription => {
                            // Called when a trial starts
                            console.log(`Trial started for subscription ${subscription.id}`, { subscription })
                        },
                        onTrialEnd: async ({ subscription }, request) => {
                            // Called when a trial ends
                            console.log(`Trial ended for subscription ${subscription.id}`, {
                                subscription,
                                request,
                            })
                        },
                        onTrialExpired: async subscription => {
                            // Called when a trial expires without conversion
                            console.log(`Trial expired for subscription ${subscription.id}`, { subscription })
                        },
                    },
                })),
                onSubscriptionComplete: async ({ event, subscription, stripeSubscription, plan }) => {
                    // Called when a subscription is successfully created
                    console.log(`Subscription ${subscription.id} created for plan ${plan.name}`, {
                        event,
                        subscription,
                        stripeSubscription,
                        plan,
                    })
                },
                onSubscriptionUpdate: async ({ event, subscription }) => {
                    // Called when a subscription is updated
                    console.log(`Subscription ${subscription.id} updated`, { event, subscription })
                },
                onSubscriptionCancel: async ({ event, subscription, stripeSubscription, cancellationDetails }) => {
                    // Called when a subscription is canceled
                    console.log(`subscription ${subscription.id} canceled`, {
                        event,
                        subscription,
                        stripeSubscription,
                        cancellationDetails,
                    })
                },
                onSubscriptionDeleted: async ({ event, subscription, stripeSubscription }) => {
                    // Called when a subscription is deleted
                    console.log(`Subscription ${subscription.id} deleted`, { event, subscription, stripeSubscription })
                },
            },
        }),
    ],
    user: {
        additionalFields: {
            firstname: {
                type: 'string',
                required: true,
            },
            lastname: {
                type: 'string',
                required: true,
            },
            role: {
                type: 'string',
                required: false,
                defaultValue: 'user',
                input: false,
            },
            country: {
                type: 'string',
                required: false,
                defaultValue: 'BE',
            },
            locale: {
                type: 'string',
                required: false,
                defaultValue: routing.defaultLocale,
            },
        },
    },
    account: {
        accountLinking: {
            enabled: true,
            allowDifferentEmails: true,
            trustedProviders: ['google', 'email-password'],
        },
    },
})

Additional context

Here's a reproductible project : https://github.com/bmichotte/better-auth-drizzle

Originally created by @bmichotte on GitHub (Nov 22, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6200 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I have the following setup : ```ts // src/db/index.ts export { accountRelations, accountsTable, sessionRelations, sessionsTable, subscriptionsTable, userRelations, userRoles, usersTable, verificationsTable, } from './auth' ``` ```ts // src/db/auth.ts export const usersTable = pgTable('users', { // ... }) // so on, all tables are named with the following pattern : namesTable = pgTable('names') ``` ```ts export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg', usePlural: true, schema: { users: schema.usersTable, sessions: schema.sessionsTable, accounts: schema.accountsTable, verifications: schema.verificationsTable, subscriptions: schema.subscriptionsTable, }, }), }) ``` This configuration **works**. ### Current vs. Expected behavior If I add ```ts experimental: { joins: true, }, ``` on my better auth config, I got the following ``` 2025-11-22T11:45:45.113Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "sessions" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate". 2025-11-22T11:45:45.113Z INFO [Better Auth]: Falling back to regular query ``` ### What version of Better Auth are you using? 1.4.0 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:55 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6031", "release": "24.6.0", "cpuCount": 16, "cpuModel": "Apple M3 Max", "totalMemory": "128.00 GB", "freeMemory": "7.19 GB" }, "node": { "version": "v22.16.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.2" }, "frameworks": [ { "name": "next", "version": "^16.0.3" }, { "name": "react", "version": "^19.2.0" } ], "databases": [ { "name": "pg", "version": "^8.16.3" }, { "name": "drizzle", "version": "^0.44.7" } ], "betterAuth": { "version": "^1.4.0", "config": { "experimental": { "joins": true }, "trustedOrigins": [ "http://localhost:3000", "jdc://" ], "emailAndPassword": { "enabled": true }, "socialProviders": { "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" } }, "plugins": [ { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } }, { "name": "admin", "config": { "id": "admin", "hooks": { "after": [ {} ] }, "endpoints": {}, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "USER_ALREADY_EXISTS": "User already exists.", "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.", "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself", "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role", "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions", "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users", "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users", "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions", "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users", "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]", "BANNED_USER": "You have been banned from this application", "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user", "NO_DATA_TO_UPDATE": "No data to update", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users", "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself", "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value" }, "schema": { "user": { "fields": { "role": { "type": "string", "required": false, "input": false }, "banned": { "type": "boolean", "defaultValue": false, "required": false, "input": false }, "banReason": { "type": "string", "required": false, "input": false }, "banExpires": { "type": "date", "required": false, "input": false } } }, "session": { "fields": { "impersonatedBy": { "type": "string", "required": false } } } } } }, { "name": "expo", "config": { "id": "expo", "hooks": { "after": [ {} ] }, "endpoints": {} } }, { "name": "stripe", "config": { "id": "stripe", "endpoints": {}, "schema": { "subscription": { "fields": { "plan": { "type": "string", "required": true }, "referenceId": { "type": "string", "required": true }, "stripeCustomerId": { "type": "string", "required": false }, "stripeSubscriptionId": { "type": "string", "required": false }, "status": { "type": "string", "defaultValue": "incomplete" }, "periodStart": { "type": "date", "required": false }, "periodEnd": { "type": "date", "required": false }, "trialStart": { "type": "date", "required": false }, "trialEnd": { "type": "date", "required": false }, "cancelAtPeriodEnd": { "type": "boolean", "required": false, "defaultValue": false }, "seats": { "type": "number", "required": false } } }, "user": { "fields": { "stripeCustomerId": { "type": "string", "required": false } } } }, "$ERROR_CODES": { "SUBSCRIPTION_NOT_FOUND": "Subscription not found", "SUBSCRIPTION_PLAN_NOT_FOUND": "Subscription plan not found", "ALREADY_SUBSCRIBED_PLAN": "You're already subscribed to this plan", "UNABLE_TO_CREATE_CUSTOMER": "Unable to create customer", "FAILED_TO_FETCH_PLANS": "Failed to fetch plans", "EMAIL_VERIFICATION_REQUIRED": "Email verification is required before you can subscribe to a plan", "SUBSCRIPTION_NOT_ACTIVE": "Subscription is not active", "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION": "Subscription is not scheduled for cancellation" } } } ], "user": { "additionalFields": { "firstname": { "type": "string", "required": true }, "lastname": { "type": "string", "required": true }, "role": { "type": "string", "required": false, "defaultValue": "user", "input": false }, "country": { "type": "string", "required": false, "defaultValue": "BE" }, "locale": { "type": "string", "required": false, "defaultValue": "fr" } } }, "account": { "accountLinking": { "enabled": true, "allowDifferentEmails": true, "trustedProviders": [ "google", "email-password" ] } } } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript const stripeClient = new Stripe(env.STRIPE_SECRET_KEY, { apiVersion: '2025-11-17.clover', }) export const auth = betterAuth({ experimental: { joins: true, }, database: drizzleAdapter(db, { provider: 'pg', usePlural: true, schema: { users: schema.usersTable, sessions: schema.sessionsTable, accounts: schema.accountsTable, verifications: schema.verificationsTable, subscriptions: schema.subscriptionsTable, sessionRelations: schema.sessionRelations, userRelations: schema.userRelations, accountRelations: schema.accountRelations, }, }), trustedOrigins: [env.BETTER_AUTH_URL, 'jdc://'], emailAndPassword: { enabled: true, sendResetPassword: async ({ user, url, token }, _request) => { console.log('sendResetPassword', user, url, token) if (url.includes('callbackURL=/invite')) { await sendInvitation(user as unknown as EmailUser, url) } else { await sendReset(user as unknown as EmailUser, url) } }, }, socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, mapProfileToUser: profile => { console.log('Google profile:', profile) return { firstname: profile.given_name, lastname: profile.family_name, } }, }, }, plugins: [ nextCookies(), admin(), expo(), stripe({ stripeClient, stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET, createCustomerOnSignUp: true, onEvent: async event => { console.log(`Stripe event received: ${event.type}`, { event }) }, subscription: { enabled: true, authorizeReference: async ({ user, session, referenceId, action }) => { console.log({ user, session, referenceId, action }) return true }, plans: plans.map(({ name, priceId, annualDiscountPriceId, freeTrial }) => ({ name, priceId, annualDiscountPriceId, freeTrial: { days: freeTrial, onTrialStart: async subscription => { // Called when a trial starts console.log(`Trial started for subscription ${subscription.id}`, { subscription }) }, onTrialEnd: async ({ subscription }, request) => { // Called when a trial ends console.log(`Trial ended for subscription ${subscription.id}`, { subscription, request, }) }, onTrialExpired: async subscription => { // Called when a trial expires without conversion console.log(`Trial expired for subscription ${subscription.id}`, { subscription }) }, }, })), onSubscriptionComplete: async ({ event, subscription, stripeSubscription, plan }) => { // Called when a subscription is successfully created console.log(`Subscription ${subscription.id} created for plan ${plan.name}`, { event, subscription, stripeSubscription, plan, }) }, onSubscriptionUpdate: async ({ event, subscription }) => { // Called when a subscription is updated console.log(`Subscription ${subscription.id} updated`, { event, subscription }) }, onSubscriptionCancel: async ({ event, subscription, stripeSubscription, cancellationDetails }) => { // Called when a subscription is canceled console.log(`subscription ${subscription.id} canceled`, { event, subscription, stripeSubscription, cancellationDetails, }) }, onSubscriptionDeleted: async ({ event, subscription, stripeSubscription }) => { // Called when a subscription is deleted console.log(`Subscription ${subscription.id} deleted`, { event, subscription, stripeSubscription }) }, }, }), ], user: { additionalFields: { firstname: { type: 'string', required: true, }, lastname: { type: 'string', required: true, }, role: { type: 'string', required: false, defaultValue: 'user', input: false, }, country: { type: 'string', required: false, defaultValue: 'BE', }, locale: { type: 'string', required: false, defaultValue: routing.defaultLocale, }, }, }, account: { accountLinking: { enabled: true, allowDifferentEmails: true, trustedProviders: ['google', 'email-password'], }, }, }) ``` ### Additional context Here's a reproductible project : https://github.com/bmichotte/better-auth-drizzle
GiteaMirror added the lockedbug labels 2026-04-17 18:57:42 -05:00
Author
Owner

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

Hi there! It seems that when enabling experimental joins, Better Auth is looking for relation definitions in your Drizzle schema that aren’t present. The error suggests updating your schema to include relations for models like “sessions” or re-generating the schema using the CLI (i.e., running “npx auth generate”) so that the necessary join mappings are in place. Please verify that your Drizzle adapter configuration includes all related models (e.g., sessionRelations, userRelations, etc.) and that their naming matches what Better Auth expects. Have you had a chance to regenerate your schema with the CLI, and did that update help resolve the issue? Tag @better-auth-agent if you would like an answer from the Agent.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3566695536 --> @better-auth-agent[bot] commented on GitHub (Nov 22, 2025): Hi there! It seems that when enabling experimental joins, Better Auth is looking for relation definitions in your Drizzle schema that aren’t present. The error suggests updating your schema to include relations for models like “sessions” or re-generating the schema using the CLI (i.e., running “npx auth generate”) so that the necessary join mappings are in place. Please verify that your Drizzle adapter configuration includes all related models (e.g., sessionRelations, userRelations, etc.) and that their naming matches what Better Auth expects. Have you had a chance to regenerate your schema with the CLI, and did that update help resolve the issue? 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

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

The error happens because when you enable experimental joins in Better Auth with Drizzle, the adapter expects your Drizzle schema to include not just tables, but also relations defined using Drizzle's relations() helper. These relations must be present and correctly mapped in the schema object you pass to drizzleAdapter. If they're missing, or if the model names don't match what Better Auth expects (e.g., "sessions" instead of "sessionsTable"), you'll get the "model not found in the query object" error and joins will silently fall back to regular queries docs adapter code.

To fix this:

  • Make sure your Drizzle schema defines all required relations using relations(), e.g., userRelations, sessionRelations, accountRelations, etc.
  • Pass these relations through the schema object to drizzleAdapter, and use the expected keys ("sessions", not "sessionsTable").
  • If you generated your schema with the Better Auth CLI, merge the generated schema with your app schema and ensure the mapping matches what Better Auth expects. If you use plural table names, set usePlural: true, but still check the keys.
  • If you haven't already, you can regenerate your schema with npx auth@latest generate to get the correct relations structure.

See the official Drizzle adapter docs for more details and examples. This should resolve the error and enable join support.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3566697869 --> @dosubot[bot] commented on GitHub (Nov 22, 2025): <!-- Answer --> The error happens because when you enable experimental joins in Better Auth with Drizzle, the adapter expects your Drizzle schema to include not just tables, but also relations defined using Drizzle's relations() helper. These relations must be present and correctly mapped in the schema object you pass to drizzleAdapter. If they're missing, or if the model names don't match what Better Auth expects (e.g., "sessions" instead of "sessionsTable"), you'll get the "model not found in the query object" error and joins will silently fall back to regular queries [docs](https://github.com/better-auth/better-auth/blob/44308bf20d431bd943a92a2ed4204a6b7d5a4182/docs/content/docs/adapters/drizzle.mdx#L47-L151) [adapter code](https://github.com/better-auth/better-auth/blob/44308bf20d431bd943a92a2ed4204a6b7d5a4182/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts#L80-L417). To fix this: - Make sure your Drizzle schema defines all required relations using relations(), e.g., userRelations, sessionRelations, accountRelations, etc. - Pass these relations through the schema object to drizzleAdapter, and use the expected keys ("sessions", not "sessionsTable"). - If you generated your schema with the Better Auth CLI, merge the generated schema with your app schema and ensure the mapping matches what Better Auth expects. If you use plural table names, set usePlural: true, but still check the keys. - If you haven't already, you can regenerate your schema with npx auth@latest generate to get the correct relations structure. See the [official Drizzle adapter docs](https://github.com/better-auth/better-auth/blob/44308bf20d431bd943a92a2ed4204a6b7d5a4182/docs/content/docs/adapters/drizzle.mdx#L47-L151) for more details and examples. This should resolve the error and enable join support. <!-- 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/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/55c7d35f-78e0-41df-91d5-bfef5d8e047f?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20error%20happens%20because%20when%20you%20enable%20experimental%20joins%20in%20Better%20Auth%20with%20Drizzle%2C%20the%20adapter%20expects%20your%20Drizzle%20schema%20to%20include%20not%20just%20tables%2C%20but%20also%20relations%20defined%20using%20Drizzle%27s%20relations%28%29%20helper.%20These%20relations%20must%20be%20present%20and%20correctly%20mapped%20in%20the%20schema%20object%20you%20pass%20to%20drizzleAdapter.%20If%20they%27re%20missing%2C%20or%20if%20the%20model%20names%20don%27t%20match%20what%20Better%20Auth%20expects%20%28e.g.%2C%20%22sessions%22%20instead%20of%20%22sessionsTable%22%29%2C%20you%27ll%20get%20the%20%22model%20not%20found%20in%20the%20query%20object%22%20error%20and%20joins%20will%20silently%20fall%20back%20to%20regular%20queries%C2%A0%5Bdocs%5D%28https%3A//github.com/better-auth/better-auth/blob/44308bf20d431bd943a92a2ed4204a6b7d5a4182/docs/content/docs/adapters/drizzle.mdx%23L47-L151%29%C2%A0%5Badapter%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/44308bf20d431bd943a92a2ed4204a6b7d5a4182/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts%23L80-L417%29.%0A%0ATo%20fix%20this%3A%0A%0A-%20Make%20sure%20your%20Drizzle%20schema%20defines%20all%20required%20relations%20using%20relations%28%29%2C%20e.g.%2C%20userRelations%2C%20sessionRelations%2C%20accountRelations%2C%20etc.%0A-%20Pass%20these%20relations%20through%20the%20schema%20object%20to%20drizzleAdapter%2C%20and%20use%20the%20expected%20keys%20%28%22sessions%22%2C%20not%20%22sessionsTable%22%29.%0A-%20If%20you%20generated%20your%20schema%20with%20the%20Better%20Auth%20CLI%2C%20merge%20the%20generated%20schema%20with%20your%20app%20schema%20and%20ensure%20the%20mapping%20matches%20what%20Better%20Auth%20expects.%20If%20you%20use%20plural%20table%20names%2C%20set%20usePlural%3A%20true%2C%20but%20still%20check%20the%20keys.%0A-%20If%20you%20haven%27t%20already%2C%20you%20can%20regenerate%20your%20schema%20with%20npx%20auth%40latest%20generate%20to%20get%20the%20correct%20relations%20structure.%0A%0ASee%20the%20%5Bofficial%20Drizzle%20adapter%20docs%5D%28https%3A//github.com/better-auth/better-auth/blob/44308bf20d431bd943a92a2ed4204a6b7d5a4182/docs/content/docs/adapters/drizzle.mdx%23L47-L151%29%20for%20more%20details%20and%20examples.%20This%20should%20resolve%20the%20error%20and%20enable%20join%20support.)&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/6200)
Author
Owner

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

Have you passed the relations to your actual drizzle db instance as well?

<!-- gh-comment-id:3566773239 --> @ping-maxwell commented on GitHub (Nov 22, 2025): Have you passed the relations to your actual drizzle db instance as well?
Author
Owner

@bmichotte commented on GitHub (Nov 22, 2025):

Have you passed the relations to your actual drizzle db instance as well?

yes
https://github.com/bmichotte/better-auth-drizzle/blob/main/src/db/schema/index.ts

<!-- gh-comment-id:3566774486 --> @bmichotte commented on GitHub (Nov 22, 2025): > Have you passed the relations to your actual drizzle db instance as well? yes https://github.com/bmichotte/better-auth-drizzle/blob/main/src/db/schema/index.ts
Author
Owner

@BetterLuke commented on GitHub (Nov 22, 2025):

Same issue with drizzle-adapter after upgrade 1.4.0.

import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { drizzle } from 'drizzle-orm/d1'
import * as schema  from './better-auth.model'

...
betterAuth({
...
     database: drizzleAdapter(drizzle(env.D1_AUTH_DB), {
        schema,
        provider: 'sqlite',
        usePlural: false,
      }),
      experimental: {
        joins: true,
      },
})

when i use google social sign-in or one-tap sign-in, i got:

2025-11-22T14:43:20.942Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "user" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate".
2025-11-22T14:43:20.942Z INFO [Better Auth]: Falling back to regular query
2025-11-22T14:43:20.961Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "user" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate".
2025-11-22T14:43:20.961Z INFO [Better Auth]: Falling back to regular query

when cancel joins everythings is normal again :

betterAuth({
...
     database: drizzleAdapter(drizzle(env.D1_AUTH_DB), {
        schema,
        provider: 'sqlite',
        usePlural: false,
      }),
//      experimental: {
 //       joins: true,
   //   },
})

<!-- gh-comment-id:3566777289 --> @BetterLuke commented on GitHub (Nov 22, 2025): Same issue with drizzle-adapter after upgrade 1.4.0. ```ts import { drizzleAdapter } from 'better-auth/adapters/drizzle' import { drizzle } from 'drizzle-orm/d1' import * as schema from './better-auth.model' ... betterAuth({ ... database: drizzleAdapter(drizzle(env.D1_AUTH_DB), { schema, provider: 'sqlite', usePlural: false, }), experimental: { joins: true, }, }) ``` when i use google social sign-in or one-tap sign-in, i got: ``` 2025-11-22T14:43:20.942Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "user" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate". 2025-11-22T14:43:20.942Z INFO [Better Auth]: Falling back to regular query 2025-11-22T14:43:20.961Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "user" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate". 2025-11-22T14:43:20.961Z INFO [Better Auth]: Falling back to regular query ``` --- when cancel `joins` everythings is normal again : ```ts betterAuth({ ... database: drizzleAdapter(drizzle(env.D1_AUTH_DB), { schema, provider: 'sqlite', usePlural: false, }), // experimental: { // joins: true, // }, }) ```
Author
Owner

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

Have you passed the relations to your actual drizzle db instance as well?

yes bmichotte/better-auth-drizzle@main/src/db/schema/index.ts

Hmm okay I'll test locally to see if I can reproduce and lyk from there.

<!-- gh-comment-id:3566777977 --> @ping-maxwell commented on GitHub (Nov 22, 2025): > > Have you passed the relations to your actual drizzle db instance as well? > > yes [bmichotte/better-auth-drizzle@`main`/src/db/schema/index.ts](https://github.com/bmichotte/better-auth-drizzle/blob/main/src/db/schema/index.ts?rgh-link-date=2025-11-22T14%3A52%3A43.000Z) Hmm okay I'll test locally to see if I can reproduce and lyk from there.
Author
Owner

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

@BetterLuke can you share your schema?

<!-- gh-comment-id:3566785104 --> @ping-maxwell commented on GitHub (Nov 22, 2025): @BetterLuke can you share your `schema`?
Author
Owner

@BetterLuke commented on GitHub (Nov 22, 2025):

@BetterLuke can you share your schema?

Hey bro, sure, here is my schma :

import { relations, sql } from 'drizzle-orm'
import { sqliteTable, text, integer, index } from 'drizzle-orm/sqlite-core'

export const user = sqliteTable('user', {
  id: text('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  emailVerified: integer('email_verified', { mode: 'boolean' }).default(false).notNull(),
  image: text('image'),
  createdAt: integer('created_at', { mode: 'timestamp_ms' })
    .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
    .notNull(),
  updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
    .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
    .$onUpdate(() => /* @__PURE__ */ new Date())
    .notNull(),
  username: text('username').unique(),
  displayUsername: text('display_username'),
})

export const session = sqliteTable(
  'session',
  {
    id: text('id').primaryKey(),
    expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),
    token: text('token').notNull().unique(),
    createdAt: integer('created_at', { mode: 'timestamp_ms' })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .notNull(),
    updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
      .$onUpdate(() => /* @__PURE__ */ new Date())
      .notNull(),
    ipAddress: text('ip_address'),
    userAgent: text('user_agent'),
    userId: text('user_id')
      .notNull()
      .references(() => user.id, { onDelete: 'cascade' }),
  },
  (table) => [index('session_userId_idx').on(table.userId)],
)

export const account = sqliteTable(
  'account',
  {
    id: text('id').primaryKey(),
    accountId: text('account_id').notNull(),
    providerId: text('provider_id').notNull(),
    userId: text('user_id')
      .notNull()
      .references(() => user.id, { onDelete: 'cascade' }),
    accessToken: text('access_token'),
    refreshToken: text('refresh_token'),
    idToken: text('id_token'),
    accessTokenExpiresAt: integer('access_token_expires_at', {
      mode: 'timestamp_ms',
    }),
    refreshTokenExpiresAt: integer('refresh_token_expires_at', {
      mode: 'timestamp_ms',
    }),
    scope: text('scope'),
    password: text('password'),
    createdAt: integer('created_at', { mode: 'timestamp_ms' })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .notNull(),
    updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
      .$onUpdate(() => /* @__PURE__ */ new Date())
      .notNull(),
  },
  (table) => [index('account_userId_idx').on(table.userId)],
)

export const verification = sqliteTable(
  'verification',
  {
    id: text('id').primaryKey(),
    identifier: text('identifier').notNull(),
    value: text('value').notNull(),
    expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),
    createdAt: integer('created_at', { mode: 'timestamp_ms' })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .notNull(),
    updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .$onUpdate(() => /* @__PURE__ */ new Date())
      .notNull(),
  },
  (table) => [index('verification_identifier_idx').on(table.identifier)],
)

export const userRelations = relations(user, ({ many }) => ({
  sessions: many(session),
  accounts: many(account),
}))

export const sessionRelations = relations(session, ({ one }) => ({
  user: one(user, {
    fields: [session.userId],
    references: [user.id],
  }),
}))

export const accountRelations = relations(account, ({ one }) => ({
  user: one(user, {
    fields: [account.userId],
    references: [user.id],
  }),
}))

After i upgrade 1.4.0, I exec pnpx @better-auth/cli@latest generate, so I got above schema file.

<!-- gh-comment-id:3566795630 --> @BetterLuke commented on GitHub (Nov 22, 2025): > [@BetterLuke](https://github.com/BetterLuke) can you share your `schema`? Hey bro, sure, here is my schma : ```ts import { relations, sql } from 'drizzle-orm' import { sqliteTable, text, integer, index } from 'drizzle-orm/sqlite-core' export const user = sqliteTable('user', { id: text('id').primaryKey(), name: text('name').notNull(), email: text('email').notNull().unique(), emailVerified: integer('email_verified', { mode: 'boolean' }).default(false).notNull(), image: text('image'), createdAt: integer('created_at', { mode: 'timestamp_ms' }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), username: text('username').unique(), displayUsername: text('display_username'), }) export const session = sqliteTable( 'session', { id: text('id').primaryKey(), expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(), token: text('token').notNull().unique(), createdAt: integer('created_at', { mode: 'timestamp_ms' }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), ipAddress: text('ip_address'), userAgent: text('user_agent'), userId: text('user_id') .notNull() .references(() => user.id, { onDelete: 'cascade' }), }, (table) => [index('session_userId_idx').on(table.userId)], ) export const account = sqliteTable( 'account', { id: text('id').primaryKey(), accountId: text('account_id').notNull(), providerId: text('provider_id').notNull(), userId: text('user_id') .notNull() .references(() => user.id, { onDelete: 'cascade' }), accessToken: text('access_token'), refreshToken: text('refresh_token'), idToken: text('id_token'), accessTokenExpiresAt: integer('access_token_expires_at', { mode: 'timestamp_ms', }), refreshTokenExpiresAt: integer('refresh_token_expires_at', { mode: 'timestamp_ms', }), scope: text('scope'), password: text('password'), createdAt: integer('created_at', { mode: 'timestamp_ms' }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), }, (table) => [index('account_userId_idx').on(table.userId)], ) export const verification = sqliteTable( 'verification', { id: text('id').primaryKey(), identifier: text('identifier').notNull(), value: text('value').notNull(), expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(), createdAt: integer('created_at', { mode: 'timestamp_ms' }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer('updated_at', { mode: 'timestamp_ms' }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), }, (table) => [index('verification_identifier_idx').on(table.identifier)], ) export const userRelations = relations(user, ({ many }) => ({ sessions: many(session), accounts: many(account), })) export const sessionRelations = relations(session, ({ one }) => ({ user: one(user, { fields: [session.userId], references: [user.id], }), })) export const accountRelations = relations(account, ({ one }) => ({ user: one(user, { fields: [account.userId], references: [user.id], }), })) ``` > After i upgrade `1.4.0`, I exec `pnpx @better-auth/cli@latest generate`, so I got above schema file.
Author
Owner

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

@BetterLuke is that everything in your schema? You're missing a lot of tables...

<!-- gh-comment-id:3566803153 --> @ping-maxwell commented on GitHub (Nov 22, 2025): @BetterLuke is that everything in your schema? You're missing a lot of tables...
Author
Owner

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

@bmichotte I was able to test out your repo and got things working. I'll give an update soon.

<!-- gh-comment-id:3566803351 --> @ping-maxwell commented on GitHub (Nov 22, 2025): @bmichotte I was able to test out your repo and got things working. I'll give an update soon.
Author
Owner

@bmichotte commented on GitHub (Nov 22, 2025):

@bmichotte I was able to test out your repo and got things working. I'll give an update soon.

@ping-maxwell The issue appears when I try to sign in if it can make some difference

<!-- gh-comment-id:3566804968 --> @bmichotte commented on GitHub (Nov 22, 2025): > [@bmichotte](https://github.com/bmichotte) I was able to test out your repo and got things working. I'll give an update soon. @ping-maxwell The issue appears when I try to sign in if it can make some difference
Author
Owner

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

@bmichotte I was able to test out your repo and got things working. I'll give an update soon.

The issue appears when I try to sign in if it can make some difference

I used our CLI to generate the schema from scratch and the warnings went away.

Also because you have additional fields, the sign-in social will fail with an unable_to_create_user error because when trying to create a user to the DB, it doesn't include all the other fields you stated in the additionalFields. You can either modify your mapProfileToUser or add a databaseHook to provide sufficient data for the DB creation call to succeed.

<!-- gh-comment-id:3566806185 --> @ping-maxwell commented on GitHub (Nov 22, 2025): > > [@bmichotte](https://github.com/bmichotte) I was able to test out your repo and got things working. I'll give an update soon. > > The issue appears when I try to sign in if it can make some difference I used our CLI to generate the schema from scratch and the warnings went away. Also because you have additional fields, the sign-in social will fail with an `unable_to_create_user` error because when trying to create a user to the DB, it doesn't include all the other fields you stated in the additionalFields. You can either modify your `mapProfileToUser` or add a databaseHook to provide sufficient data for the DB creation call to succeed.
Author
Owner

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

I recommend regenerating the schema from our CLI to compare.

<!-- gh-comment-id:3566806610 --> @ping-maxwell commented on GitHub (Nov 22, 2025): I recommend regenerating the schema from our CLI to compare.
Author
Owner

@BetterLuke commented on GitHub (Nov 22, 2025):

@BetterLuke is that everything in your schema? You're missing a lot of tables...

Yes, this is all my schema. I will try re-generate schema or re migrate table.

<!-- gh-comment-id:3566807300 --> @BetterLuke commented on GitHub (Nov 22, 2025): > [@BetterLuke](https://github.com/BetterLuke) is that everything in your schema? You're missing a lot of tables... Yes, this is all my schema. I will try re-generate schema or re migrate table.
Author
Owner

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

@BetterLuke is that everything in your schema? You're missing a lot of tables...

Yes, this is all my schema. I will try re-generate schema or re migrate table.

Yeah it's not right, you're missing the session, account & verification tables. As well as the drizzle relations.

Let me know how it goes once you try to re-generated, it could be a bug with our CLI but I doubt it.

<!-- gh-comment-id:3566807750 --> @ping-maxwell commented on GitHub (Nov 22, 2025): > > [@BetterLuke](https://github.com/BetterLuke) is that everything in your schema? You're missing a lot of tables... > > Yes, this is all my schema. I will try re-generate schema or re migrate table. Yeah it's not right, you're missing the `session`, `account` & `verification` tables. As well as the drizzle relations. Let me know how it goes once you try to re-generated, it could be a bug with our CLI but I doubt it.
Author
Owner

@bmichotte commented on GitHub (Nov 22, 2025):

I used our CLI to generate the schema from scratch and the warnings went away.

Yes, but then you have the names from better-auth (user, session, etc.). The problem arises if you do not have the same table names and you use the adapter schema.

Also because you have additional fields, the sign-in social will fail with an unable_to_create_user error because when trying to create a user to the DB, it doesn't include all the other fields you stated in the additionalFields. You can either modify your mapProfileToUser or add a databaseHook to provide sufficient data for the DB creation call to succeed.

When I made the reproduction, I added github because it's the easiest for us. In my real project, I only have google as social provider with the following

 socialProviders: {
        google: {
            clientId: env.GOOGLE_CLIENT_ID,
            clientSecret: env.GOOGLE_CLIENT_SECRET,
            mapProfileToUser: profile => {
                return {
                    firstname: profile.given_name,
                    lastname: profile.family_name,
                }
            },
        },
    },
<!-- gh-comment-id:3566811157 --> @bmichotte commented on GitHub (Nov 22, 2025): > I used our CLI to generate the schema from scratch and the warnings went away. Yes, but then you have the names from better-auth (user, session, etc.). The problem arises if you do not have the same table names and you use the adapter schema. > Also because you have additional fields, the sign-in social will fail with an `unable_to_create_user` error because when trying to create a user to the DB, it doesn't include all the other fields you stated in the additionalFields. You can either modify your `mapProfileToUser` or add a databaseHook to provide sufficient data for the DB creation call to succeed. When I made the reproduction, I added github because it's the easiest for us. In my real project, I only have google as social provider with the following ```ts socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, mapProfileToUser: profile => { return { firstname: profile.given_name, lastname: profile.family_name, } }, }, }, ```
Author
Owner

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

The reason you're getting warnings is because under the hood we check if db.query.<table> exists.
Since in better-auth, we see it as "sessions" not "sessionsTable" this check is failing.

For context, the db.query is only when experimental joins is enabled. Otherwise we do not use the Drizzle query API to perform DB actions.

Which is why you're receiving this error.

It's possible you can try something like this:

Image

(Which also means updating your schema mapping in the drizzle-adapter, and removing usePlural)

@bmichotte

<!-- gh-comment-id:3566822768 --> @ping-maxwell commented on GitHub (Nov 22, 2025): The reason you're getting warnings is because under the hood we check if `db.query.<table>` exists. Since in better-auth, we see it as "sessions" not "sessionsTable" this check is failing. For context, the `db.query` is only when experimental joins is enabled. Otherwise we do not use the Drizzle query API to perform DB actions. Which is why you're receiving this error. It's possible you can try something like this: <img width="581" height="79" alt="Image" src="https://github.com/user-attachments/assets/51e52316-7fdd-46a1-a120-fde7c9e289f4" /> (Which also means updating your schema mapping in the drizzle-adapter, and removing `usePlural`) @bmichotte
Author
Owner

@BetterLuke commented on GitHub (Nov 22, 2025):

@BetterLuke is that everything in your schema? You're missing a lot of tables...@BetterLuke 这就是你模式中的一切吗?你错过了很多桌子...

Yes, this is all my schema. I will try re-generate schema or re migrate table.是的,这就是我的全部架构。我将尝试重新生成架构或重新迁移表。

Yeah it's not right, you're missing the session, account & verification tables. As well as the drizzle relations.是的,这是不对的,你缺少 , & 表。还有毛毛雨的关系。

Let me know how it goes once you try to re-generated, it could be a bug with our CLI but I doubt it.让我知道当您尝试重新生成时情况如何,这可能是我们的 CLI 的一个错误,但我对此表示怀疑。

I retried locally, and the behavior is still consistent with what I observed before. As a temporary workaround, I’ve commented out the new joins feature. I’ll continue testing, and if I discover anything new, I’ll update here. Thanks again for your work!

<!-- gh-comment-id:3566833403 --> @BetterLuke commented on GitHub (Nov 22, 2025): > > > [@BetterLuke](https://github.com/BetterLuke) is that everything in your schema? You're missing a lot of tables...@BetterLuke 这就是你模式中的一切吗?你错过了很多桌子... > > > > > > Yes, this is all my schema. I will try re-generate schema or re migrate table.是的,这就是我的全部架构。我将尝试重新生成架构或重新迁移表。 > > Yeah it's not right, you're missing the `session`, `account` & `verification` tables. As well as the drizzle relations.是的,这是不对的,你缺少 , & 表。还有毛毛雨的关系。 > > Let me know how it goes once you try to re-generated, it could be a bug with our CLI but I doubt it.让我知道当您尝试重新生成时情况如何,这可能是我们的 CLI 的一个错误,但我对此表示怀疑。 I retried locally, and the behavior is still consistent with what I observed before. As a temporary workaround, I’ve commented out the new joins feature. I’ll continue testing, and if I discover anything new, I’ll update here. Thanks again for your work!
Author
Owner

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

Sure.

Feel free to share your auth config too, I can possibly find out the cause.

<!-- gh-comment-id:3566844987 --> @ping-maxwell commented on GitHub (Nov 22, 2025): Sure. Feel free to share your auth config too, I can possibly find out the cause.
Author
Owner

@bmichotte commented on GitHub (Nov 22, 2025):

The reason you're getting warnings is because under the hood we check if db.query.<table> exists. Since in better-auth, we see it as "sessions" not "sessionsTable" this check is failing.

This makes sense

It's possible you can try something like this:

Image (Which also means updating your schema mapping in the drizzle-adapter, and removing `usePlural`)

I guess I'm missing something. So, what I have is now

export const auth = betterAuth({
    experimental: {
        joins: true,
    },
    database: drizzleAdapter(db, {
        provider: 'pg',
        schema,
    }),
   // ....
      plugins: [
           stripe({
              schema: {
                  subscription: { modelName: 'subscriptionsTable' },
              },
        // ...
    })],
  user: {
        modelName: 'usersTable',
        additionalFields: {
            // ...
        },
    },
    account: {
        modelName: 'accountsTable',
        accountLinking: {
           // ...
        },
    },
    session: {
        modelName: 'sessionsTable',
    },
    verification: {
        modelName: 'verificationsTable',
    },
})

and with that configuration, when I try to login

2025-11-22T16:17:58.936Z ERROR [Better Auth]: Better auth was unable to query your database.
Error:  TypeError: Cannot read properties of undefined (reading 'referencedTable')
    at ignore-listed frames

Edit: I don't have the error with the same configuration and the experimental join commented

<!-- gh-comment-id:3566855697 --> @bmichotte commented on GitHub (Nov 22, 2025): > The reason you're getting warnings is because under the hood we check if `db.query.<table>` exists. Since in better-auth, we see it as "sessions" not "sessionsTable" this check is failing. This makes sense > It's possible you can try something like this: > > <img alt="Image" width="581" height="79" src="https://private-user-images.githubusercontent.com/145994855/517735072-51e52316-7fdd-46a1-a120-fde7c9e289f4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjM4MjgwNTgsIm5iZiI6MTc2MzgyNzc1OCwicGF0aCI6Ii8xNDU5OTQ4NTUvNTE3NzM1MDcyLTUxZTUyMzE2LTdmZGQtNDZhMS1hMTIwLWZkZTdjOWUyODlmNC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUxMTIyJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MTEyMlQxNjA5MThaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0xYzA3ODM0NjJhZjhmMzMxNzg0NDBiMTM4MzE0YWM0MmEwZGQyYmFkMDg2ZTExNzI4ODgwMGQzMzM1OWQ0YTc3JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.1vVuyxirVyGUDKpQCHyPVh2EPmUIim4FChuU-B75lFQ"> > (Which also means updating your schema mapping in the drizzle-adapter, and removing `usePlural`) I guess I'm missing something. So, what I have is now ```ts export const auth = betterAuth({ experimental: { joins: true, }, database: drizzleAdapter(db, { provider: 'pg', schema, }), // .... plugins: [ stripe({ schema: { subscription: { modelName: 'subscriptionsTable' }, }, // ... })], user: { modelName: 'usersTable', additionalFields: { // ... }, }, account: { modelName: 'accountsTable', accountLinking: { // ... }, }, session: { modelName: 'sessionsTable', }, verification: { modelName: 'verificationsTable', }, }) ``` and with that configuration, when I try to login ``` 2025-11-22T16:17:58.936Z ERROR [Better Auth]: Better auth was unable to query your database. Error: TypeError: Cannot read properties of undefined (reading 'referencedTable') at ignore-listed frames ``` Edit: I don't have the error with the same configuration and the experimental join commented
Author
Owner

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

@bmichotte can you push those changes to your test repo and I can check it out?

<!-- gh-comment-id:3566889459 --> @ping-maxwell commented on GitHub (Nov 22, 2025): @bmichotte can you push those changes to your test repo and I can check it out?
Author
Owner

@bmichotte commented on GitHub (Nov 22, 2025):

@bmichotte can you push those changes to your test repo and I can check it out?

Sure @ping-maxwell, I just pushed them

<!-- gh-comment-id:3566896424 --> @bmichotte commented on GitHub (Nov 22, 2025): > [@bmichotte](https://github.com/bmichotte) can you push those changes to your test repo and I can check it out? Sure @ping-maxwell, I just pushed them
Author
Owner

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

@bmichotte The issue was that these needs to be updated:

Image
<!-- gh-comment-id:3566917083 --> @ping-maxwell commented on GitHub (Nov 22, 2025): @bmichotte The issue was that these needs to be updated: <img width="624" height="366" alt="Image" src="https://github.com/user-attachments/assets/7f9697ae-aca2-4357-b5f0-0654e49132c6" />
Author
Owner

@bmichotte commented on GitHub (Nov 22, 2025):

@ping-maxwell yes, you're right, it fixes the issue now.

I've updated the example repository for future reference

<!-- gh-comment-id:3566922875 --> @bmichotte commented on GitHub (Nov 22, 2025): @ping-maxwell yes, you're right, it fixes the issue now. I've updated the example repository for future reference
Author
Owner

@ziyak97 commented on GitHub (Nov 22, 2025):

I am facing the same issue

2025-11-22T20:17:49.312Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "session" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate".

import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { betterAuth } from "better-auth/minimal";
import { db } from "@/db";
import {
  account,
  accountRelations,
  session,
  sessionRelations,
  user,
  userRelations,
  verification,
} from "@/db/schema/auth";
import { env } from "@/env";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "sqlite",
    schema: {
      user,
      session,
      account,
      verification,
      userRelations,
      sessionRelations,
      accountRelations,
    },
  }),
  experimental: { joins: true },
  baseURL: env.BETTER_AUTH_URL,
  secret: env.BETTER_AUTH_SECRET,
  socialProviders: {
    google: {
      prompt: "select_account",
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24, // 24 hours
  },
  advanced: {
    database: {
      generateId: () => crypto.randomUUID(),
    },
  },
  callbacks: {
    afterSignIn: {
      redirect: "/onboarding",
    },
  },

});
import { relations, sql } from "drizzle-orm";
import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const user = sqliteTable("user", {
  id: text("id").primaryKey(),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  emailVerified: integer("email_verified", { mode: "boolean" })
    .default(false)
    .notNull(),
  image: text("image"),
  createdAt: integer("created_at", { mode: "timestamp_ms" })
    .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
    .notNull(),
  updatedAt: integer("updated_at", { mode: "timestamp_ms" })
    .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
    .$onUpdate(() => /* @__PURE__ */ new Date())
    .notNull(),
  role: text("role"),
  banned: integer("banned", { mode: "boolean" }).default(false),
  banReason: text("ban_reason"),
  banExpires: integer("ban_expires", { mode: "timestamp_ms" }),
});

export const session = sqliteTable(
  "session",
  {
    id: text("id").primaryKey(),
    expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
    token: text("token").notNull().unique(),
    createdAt: integer("created_at", { mode: "timestamp_ms" })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .notNull(),
    updatedAt: integer("updated_at", { mode: "timestamp_ms" })
      .$onUpdate(() => /* @__PURE__ */ new Date())
      .notNull(),
    ipAddress: text("ip_address"),
    userAgent: text("user_agent"),
    userId: text("user_id")
      .notNull()
      .references(() => user.id, { onDelete: "cascade" }),
    impersonatedBy: text("impersonated_by"),
  },
  (table) => [index("session_userId_idx").on(table.userId)],
);

export const account = sqliteTable(
  "account",
  {
    id: text("id").primaryKey(),
    accountId: text("account_id").notNull(),
    providerId: text("provider_id").notNull(),
    userId: text("user_id")
      .notNull()
      .references(() => user.id, { onDelete: "cascade" }),
    accessToken: text("access_token"),
    refreshToken: text("refresh_token"),
    idToken: text("id_token"),
    accessTokenExpiresAt: integer("access_token_expires_at", {
      mode: "timestamp_ms",
    }),
    refreshTokenExpiresAt: integer("refresh_token_expires_at", {
      mode: "timestamp_ms",
    }),
    scope: text("scope"),
    password: text("password"),
    createdAt: integer("created_at", { mode: "timestamp_ms" })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .notNull(),
    updatedAt: integer("updated_at", { mode: "timestamp_ms" })
      .$onUpdate(() => /* @__PURE__ */ new Date())
      .notNull(),
  },
  (table) => [index("account_userId_idx").on(table.userId)],
);

export const verification = sqliteTable(
  "verification",
  {
    id: text("id").primaryKey(),
    identifier: text("identifier").notNull(),
    value: text("value").notNull(),
    expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
    createdAt: integer("created_at", { mode: "timestamp_ms" })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .notNull(),
    updatedAt: integer("updated_at", { mode: "timestamp_ms" })
      .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
      .$onUpdate(() => /* @__PURE__ */ new Date())
      .notNull(),
  },
  (table) => [index("verification_identifier_idx").on(table.identifier)],
);

export const userRelations = relations(user, ({ many }) => ({
  sessions: many(session),
  accounts: many(account),
}));

export const sessionRelations = relations(session, ({ one }) => ({
  user: one(user, {
    fields: [session.userId],
    references: [user.id],
  }),
}));

export const accountRelations = relations(account, ({ one }) => ({
  user: one(user, {
    fields: [account.userId],
    references: [user.id],
  }),
}));

generated the schema using -> npx @better-auth/cli generate

@ping-maxwell any idea what i have done different/wrong here?

<!-- gh-comment-id:3567019631 --> @ziyak97 commented on GitHub (Nov 22, 2025): I am facing the same issue 2025-11-22T20:17:49.312Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "session" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate". ``` import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { betterAuth } from "better-auth/minimal"; import { db } from "@/db"; import { account, accountRelations, session, sessionRelations, user, userRelations, verification, } from "@/db/schema/auth"; import { env } from "@/env"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "sqlite", schema: { user, session, account, verification, userRelations, sessionRelations, accountRelations, }, }), experimental: { joins: true }, baseURL: env.BETTER_AUTH_URL, secret: env.BETTER_AUTH_SECRET, socialProviders: { google: { prompt: "select_account", clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, // 24 hours }, advanced: { database: { generateId: () => crypto.randomUUID(), }, }, callbacks: { afterSignIn: { redirect: "/onboarding", }, }, }); ``` ``` import { relations, sql } from "drizzle-orm"; import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; export const user = sqliteTable("user", { id: text("id").primaryKey(), name: text("name").notNull(), email: text("email").notNull().unique(), emailVerified: integer("email_verified", { mode: "boolean" }) .default(false) .notNull(), image: text("image"), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), role: text("role"), banned: integer("banned", { mode: "boolean" }).default(false), banReason: text("ban_reason"), banExpires: integer("ban_expires", { mode: "timestamp_ms" }), }); export const session = sqliteTable( "session", { id: text("id").primaryKey(), expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), token: text("token").notNull().unique(), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), ipAddress: text("ip_address"), userAgent: text("user_agent"), userId: text("user_id") .notNull() .references(() => user.id, { onDelete: "cascade" }), impersonatedBy: text("impersonated_by"), }, (table) => [index("session_userId_idx").on(table.userId)], ); export const account = sqliteTable( "account", { id: text("id").primaryKey(), accountId: text("account_id").notNull(), providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() .references(() => user.id, { onDelete: "cascade" }), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), accessTokenExpiresAt: integer("access_token_expires_at", { mode: "timestamp_ms", }), refreshTokenExpiresAt: integer("refresh_token_expires_at", { mode: "timestamp_ms", }), scope: text("scope"), password: text("password"), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), }, (table) => [index("account_userId_idx").on(table.userId)], ); export const verification = sqliteTable( "verification", { id: text("id").primaryKey(), identifier: text("identifier").notNull(), value: text("value").notNull(), expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), }, (table) => [index("verification_identifier_idx").on(table.identifier)], ); export const userRelations = relations(user, ({ many }) => ({ sessions: many(session), accounts: many(account), })); export const sessionRelations = relations(session, ({ one }) => ({ user: one(user, { fields: [session.userId], references: [user.id], }), })); export const accountRelations = relations(account, ({ one }) => ({ user: one(user, { fields: [account.userId], references: [user.id], }), })); ``` generated the schema using -> npx @better-auth/cli generate @ping-maxwell any idea what i have done different/wrong here?
Author
Owner

@ziyak97 commented on GitHub (Nov 22, 2025):

Btw i removed the -> experimental: { joins: true }, and things are working now. Lmk if there is a fix for this will enable it again.

<!-- gh-comment-id:3567048079 --> @ziyak97 commented on GitHub (Nov 22, 2025): Btw i removed the -> `experimental: { joins: true },` and things are working now. Lmk if there is a fix for this will enable it again.
Author
Owner

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

The warning comes when you don't properly include all your schemas in the drizzle instance.

drizzle(db, {schema}) <- make sure it'a all there

<!-- gh-comment-id:3567143408 --> @ping-maxwell commented on GitHub (Nov 22, 2025): The warning comes when you don't properly include all your schemas in the drizzle instance. `drizzle(db, {schema})` <- make sure it'a all there
Author
Owner

@ziyak97 commented on GitHub (Nov 23, 2025):

The warning comes when you don't properly include all your schemas in the drizzle instance.

drizzle(db, {schema}) <- make sure it'a all there

Yea its all there the same can be referenced in the two code snippets i shared above. Am i missing something?

Also my error is

2025-11-23T01:18:55.552Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "session" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate".

I am not sure why this warning disappears when i remove ->

experimental: {
  joins: true
},

Should it not happen by default regardless of this flag?

<!-- gh-comment-id:3567309318 --> @ziyak97 commented on GitHub (Nov 23, 2025): > The warning comes when you don't properly include all your schemas in the drizzle instance. > > `drizzle(db, {schema})` <- make sure it'a all there Yea its all there the same can be referenced in the two code snippets i shared above. Am i missing something? Also my error is 2025-11-23T01:18:55.552Z ERROR [Better Auth]: [# Drizzle Adapter]: The model "session" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth generate". I am not sure why this warning disappears when i remove -> ``` experimental: { joins: true }, ``` Should it not happen by default regardless of this flag?
Author
Owner

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

It's not shown in your code snippets.
I'm not referring to the drizzle adapter, I'm referring to the drizzle instance.

Where you define db is where the drizzle instance is.

<!-- gh-comment-id:3568167674 --> @ping-maxwell commented on GitHub (Nov 23, 2025): It's not shown in your code snippets. I'm not referring to the drizzle adapter, I'm referring to the drizzle instance. Where you define `db` is where the drizzle instance is.
Author
Owner

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

I am not sure why this warning disappears when i remove ->

Please read this: https://github.com/better-auth/better-auth/issues/6200#issuecomment-3566822768

<!-- gh-comment-id:3568168417 --> @ping-maxwell commented on GitHub (Nov 23, 2025): > I am not sure why this warning disappears when i remove -> Please read this: https://github.com/better-auth/better-auth/issues/6200#issuecomment-3566822768
Author
Owner

@ziyak97 commented on GitHub (Nov 23, 2025):

It's not shown in your code snippets. I'm not referring to the drizzle adapter, I'm referring to the drizzle instance.

Where you define db is where the drizzle instance is.

Thank you this worked. So in my case i was using the builder api everywhere, looks like better auth internally use the Queries API of Drizzle for joins. I think before joins this was not the case cause it worked fine prior?

If this is the case maybe it can be called out better (in the docs) so that others doing the same will not face this issue?

Maybe it has already been called out but I could not find it.

Thanks for the help!

<!-- gh-comment-id:3568315582 --> @ziyak97 commented on GitHub (Nov 23, 2025): > It's not shown in your code snippets. I'm not referring to the drizzle adapter, I'm referring to the drizzle instance. > > Where you define `db` is where the drizzle instance is. Thank you this worked. So in my case i was using the builder api everywhere, looks like better auth internally use the [Queries API](https://orm.drizzle.team/docs/rqb) of Drizzle for joins. I think before joins this was not the case cause it worked fine prior? If this is the case maybe it can be called out better (in the docs) so that others doing the same will not face this issue? Maybe it has already been called out but I could not find it. Thanks for the help!
Author
Owner

@KinanLak commented on GitHub (Nov 24, 2025):

The fix for me was to explicitly pass schema when creating the db instance with Drizzle.

// db.ts

import { env } from "@/lib/env";
import { drizzle } from "drizzle-orm/node-postgres";

import * as schema from "@/db/schema";
// Be sure to import both the better-auth schema and your custom schemas.

export const db = drizzle({
    connection: {
        host: env.PG_HOST,
        port: env.PG_PORT,
        user: env.PG_USER,
        password: env.PG_PASSWORD,
        database: env.PG_DB,
        ssl: env.PG_SSL,
    },
    schema, // <-- Add this
});
// @/db/schema/index.ts

export * from "./auth-schema"; // better-auth schemas
export * from "./app-schema";  // your custom schemas

After adding this, enabling joins works as expected:

experimental: {
    joins: true,
},
<!-- gh-comment-id:3568528725 --> @KinanLak commented on GitHub (Nov 24, 2025): The fix for me was to explicitly pass `schema` when creating the `db` instance with Drizzle. ```ts // db.ts import { env } from "@/lib/env"; import { drizzle } from "drizzle-orm/node-postgres"; import * as schema from "@/db/schema"; // Be sure to import both the better-auth schema and your custom schemas. export const db = drizzle({ connection: { host: env.PG_HOST, port: env.PG_PORT, user: env.PG_USER, password: env.PG_PASSWORD, database: env.PG_DB, ssl: env.PG_SSL, }, schema, // <-- Add this }); ``` ```ts // @/db/schema/index.ts export * from "./auth-schema"; // better-auth schemas export * from "./app-schema"; // your custom schemas ``` After adding this, enabling joins works as expected: ```ts experimental: { joins: true, }, ```
Author
Owner

@ziyak97 commented on GitHub (Nov 24, 2025):

The fix for me was to explicitly pass schema when creating the db instance with Drizzle.

// db.ts

import { env } from "@/lib/env";
import { drizzle } from "drizzle-orm/node-postgres";

import * as schema from "@/db/schema";
// Be sure to import both the better-auth schema and your custom schemas.

export const db = drizzle({
connection: {
host: env.PG_HOST,
port: env.PG_PORT,
user: env.PG_USER,
password: env.PG_PASSWORD,
database: env.PG_DB,
ssl: env.PG_SSL,
},
schema, // <-- Add this
});
// @/db/schema/index.ts

export * from "./auth-schema"; // better-auth schemas
export * from "./app-schema"; // your custom schemas
After adding this, enabling joins works as expected:

experimental: {
joins: true,
},

Just one thing to correct here, you don't need your other app schemas if you don't want to use Queries API for your other schemas. You would just need the betterauth auth schema.

I think maybe it would make sense to even remove the Queries API from betterauth joins so that people don't have this dependency?

Imo since it is not needed without joins, I don't think it should be needed with joins as well.

<!-- gh-comment-id:3570277485 --> @ziyak97 commented on GitHub (Nov 24, 2025): > The fix for me was to explicitly pass `schema` when creating the `db` instance with Drizzle. > > // db.ts > > import { env } from "@/lib/env"; > import { drizzle } from "drizzle-orm/node-postgres"; > > import * as schema from "@/db/schema"; > // Be sure to import both the better-auth schema and your custom schemas. > > export const db = drizzle({ > connection: { > host: env.PG_HOST, > port: env.PG_PORT, > user: env.PG_USER, > password: env.PG_PASSWORD, > database: env.PG_DB, > ssl: env.PG_SSL, > }, > schema, // <-- Add this > }); > // @/db/schema/index.ts > > export * from "./auth-schema"; // better-auth schemas > export * from "./app-schema"; // your custom schemas > After adding this, enabling joins works as expected: > > experimental: { > joins: true, > }, Just one thing to correct here, you don't need your other app schemas if you don't want to use [Queries API](https://orm.drizzle.team/docs/rqb) for your other schemas. You would just need the betterauth auth schema. I think maybe it would make sense to even remove the [Queries API](https://orm.drizzle.team/docs/rqb) from betterauth joins so that people don't have this dependency? Imo since it is not needed without joins, I don't think it should be needed with joins as well.
Author
Owner

@BetterLuke commented on GitHub (Nov 24, 2025):

The fix for me was to explicitly pass schema when creating the db instance with Drizzle.对我来说,修复方法是在使用 Drizzle 创建实例时显式传递。

// db.ts

import { env } from "@/lib/env";
import { drizzle } from "drizzle-orm/node-postgres";

import * as schema from "@/db/schema";
// Be sure to import both the better-auth schema and your custom schemas.

export const db = drizzle({
connection: {
host: env.PG_HOST,
port: env.PG_PORT,
user: env.PG_USER,
password: env.PG_PASSWORD,
database: env.PG_DB,
ssl: env.PG_SSL,
},
schema, // <-- Add this
});
// @/db/schema/index.ts

export * from "./auth-schema"; // better-auth schemas
export * from "./app-schema"; // your custom schemas
After adding this, enabling joins works as expected:添加此后,启用连接将按预期工作:

experimental: {
joins: true,
},

Thanks bro, you save me.

<!-- gh-comment-id:3571884824 --> @BetterLuke commented on GitHub (Nov 24, 2025): > The fix for me was to explicitly pass `schema` when creating the `db` instance with Drizzle.对我来说,修复方法是在使用 Drizzle 创建实例时显式传递。 > > // db.ts > > import { env } from "@/lib/env"; > import { drizzle } from "drizzle-orm/node-postgres"; > > import * as schema from "@/db/schema"; > // Be sure to import both the better-auth schema and your custom schemas. > > export const db = drizzle({ > connection: { > host: env.PG_HOST, > port: env.PG_PORT, > user: env.PG_USER, > password: env.PG_PASSWORD, > database: env.PG_DB, > ssl: env.PG_SSL, > }, > schema, // <-- Add this > }); > // @/db/schema/index.ts > > export * from "./auth-schema"; // better-auth schemas > export * from "./app-schema"; // your custom schemas > After adding this, enabling joins works as expected:添加此后,启用连接将按预期工作: > > experimental: { > joins: true, > }, Thanks bro, you save me.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27765