Error with custom field mapping. whereClause id getting undefined value

I'm migrating from Auth0 to better-auth. In my existing project users table called UsersView (don't ask). And the primary key is userId (instead of just id) Here is my config:
export const auth = betterAuth({
user: {
modelName: 'UsersView',
fields: {
name: 'firstName',
id: 'userId',
email: 'email',
image: 'avatarUrl',
},
},
session: {
modelName: 'auth_sessions',
},
account: {
modelName: 'auth_account',
},
verification: {
modelName: 'auth_verification',
},
database: prismaAdapter(prisma, {
provider: 'mysql',
}),
plugins: [
emailOTP({
async sendVerificationOTP({ email, otp, type }) {
if (type === 'sign-in') {
console.log(email, otp);
}
// Implement the sendVerificationOTP method to send the OTP to the user's email address //
},
}),
],
trustedOrigins: ['***'],
});
export const auth = betterAuth({
user: {
modelName: 'UsersView',
fields: {
name: 'firstName',
id: 'userId',
email: 'email',
image: 'avatarUrl',
},
},
session: {
modelName: 'auth_sessions',
},
account: {
modelName: 'auth_account',
},
verification: {
modelName: 'auth_verification',
},
database: prismaAdapter(prisma, {
provider: 'mysql',
}),
plugins: [
emailOTP({
async sendVerificationOTP({ email, otp, type }) {
if (type === 'sign-in') {
console.log(email, otp);
}
// Implement the sendVerificationOTP method to send the OTP to the user's email address //
},
}),
],
trustedOrigins: ['***'],
});
The OTP code is generating succesfuly: And here is the db record that I'm getting in verifications table: (see screenshot) Now when I submit the code I'm getting an error
# SERVER_ERROR: PrismaClientValidationError:
Invalid `db[getModelName(model)].update()` invocation in
/Users/ilyalibin/Dev/thrive-be/node_modules/better-auth/dist/adapters/prisma-adapter/index.mjs:217:52
# SERVER_ERROR: PrismaClientValidationError:
Invalid `db[getModelName(model)].update()` invocation in
/Users/ilyalibin/Dev/thrive-be/node_modules/better-auth/dist/adapters/prisma-adapter/index.mjs:217:52
Argument `where` of type UsersViewWhereUniqueInput needs at least one of `userId` arguments. Available options are marked with
Argument `where` of type UsersViewWhereUniqueInput needs at least one of `userId` arguments. Available options are marked with
When I console log the whereClause, here is what I see.
ANY /hono/api/auth/sign-in/email-otp (λ: honoApp)
whereClause { id: undefined }
data {
model: 'user',
update: { emailVerified: true },
where: [ { field: 'id', value: undefined } ]
}
where [ { field: 'id', value: undefined } ]
ANY /hono/api/auth/sign-in/email-otp (λ: honoApp)
whereClause { id: undefined }
data {
model: 'user',
update: { emailVerified: true },
where: [ { field: 'id', value: undefined } ]
}
where [ { field: 'id', value: undefined } ]
Please advice
No description
5 Replies
ilya
ilyaOP2mo ago
version "better-auth": "^1.2.3",
ilya
ilyaOP2mo ago
I think this is where my issue comes from https://github.com/better-auth/better-auth/blob/f90581d7ab0493fb58d3c2654c326f6f28a684b3/packages/better-auth/src/plugins/email-otp/index.ts#L488 It tries to update user and set
data: {
emailVerified: true
}
data: {
emailVerified: true
}
But it fails because it getting user id from user.user.id instead of user.user.userId... does the id can be mapped to userId in a simple fix or I'll have to add a new column to my db?
No description
bekacru
bekacru2mo ago
id can't be mapped to something else
ilya
ilyaOP2mo ago
@bekacru I've added id column as a primary key, and moved userId column to be not nullable "alias". The login for existing user is now working as expected as it just fetching the existing user by email. The sign up flow however fails, because it can't populate userId required field. Refactoring the whole codebase form userId to id would be taugh. The only workaround that I can use is to somehow make better-auth create a new user with userId=id. I was looking into the documentation for additional fields. Is there a way to somehow make better-auth populate userId with id? This is my only blocker at the moment. I'm 99% close to ditch Auth0.
No description
ilya
ilyaOP2mo ago
A Before Hook maybe? Anyone looking for a solution, here is how it's done
user: {
modelName: 'UsersView',
fields: {
name: 'firstName',
email: 'email',
image: 'avatarUrl',
},
additionalFields: {
userId: {
type: 'string',
},
subscriptionStatus: {
type: 'string',
},
primaryProvider: {
type: 'string',
},
},
},
databaseHooks: {
user: {
create: {
before: async (user) => {
const userId = generateId(24);
return {
data: {
...user,
id: userId,
userId, // id alias
subscriptionStatus: SubscriptionStatus.FREE,
primaryProvider: IdentityProvider.email,
},
};
},
},
},
},
user: {
modelName: 'UsersView',
fields: {
name: 'firstName',
email: 'email',
image: 'avatarUrl',
},
additionalFields: {
userId: {
type: 'string',
},
subscriptionStatus: {
type: 'string',
},
primaryProvider: {
type: 'string',
},
},
},
databaseHooks: {
user: {
create: {
before: async (user) => {
const userId = generateId(24);
return {
data: {
...user,
id: userId,
userId, // id alias
subscriptionStatus: SubscriptionStatus.FREE,
primaryProvider: IdentityProvider.email,
},
};
},
},
},
},

Did you find this page helpful?