passkey plugin not respecting uuid id generation in version 1.4.7 #2548

Closed
opened 2026-03-13 10:02:11 -05:00 by GiteaMirror · 8 comments
Owner

Originally created by @RVP97 on GitHub (Dec 16, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Upgrade from 1.4.6 to 1.4.7 and try to create a new passkey.

It will throw following error

ERROR [Better Auth]: Failed to verify registration error: invalid input syntax for type uuid: "4TnQOJFeOfSaKbChINuNHDObycZ7siXh"
at ignore-listed frames {
length: 164,
severity: 'ERROR',
code: '22P02',
detail: undefined,
hint: undefined,
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: "unnamed portal parameter $1 = '...'",
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'uuid.c',
line: '141',
routine: 'string_to_uuid'
}

Current vs. Expected behavior

It should successfully create passkey. Right now, it gives out error, inserts into db put does not work if I try to sign in.

What version of Better Auth are you using?

1.4.7

System info

❯ npx @better-auth/cli info --json
{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.0.0: Mon Aug 25 21:17:51 PDT 2025; root:xnu-12377.1.9~3/RELEASE_ARM64_T6000",
    "release": "25.0.0",
    "cpuCount": 10,
    "cpuModel": "Apple M1 Pro",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.16 GB"
  },
  "node": {
    "version": "v22.12.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.5.2"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.0.10"
    },
    {
      "name": "react",
      "version": "19.2.3"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.16.3"
    },
    {
      "name": "postgres",
      "version": "^3.4.7"
    }
  ],
  "betterAuth": {
    "version": "^1.4.7",
    "config": null
  }
}

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

Other

Auth config (if applicable)

import { passkey } from "@better-auth/passkey";
import { appInvite } from "@better-auth-extended/app-invite";
import bcrypt from "bcryptjs";
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";
import { admin, lastLoginMethod, twoFactor } from "better-auth/plugins";
import { Pool } from "pg";
import { Resend } from "resend";
import AppInvitationEmail from "@/components/emails/app-invitation";
import ConfirmEmail from "@/components/emails/confirm-email";
import PasswordResetEmail from "@/components/emails/password-reset";
import { deleteUserCache } from "@/lib/redis/cache-utils";
import { connectRedis } from "@/lib/redis/client";

const resend = new Resend(process.env.RESEND_API_KEY);

if (!process.env.DATABASE_URL) {
	throw new Error("DATABASE_URL environment variable is required");
}

if (!process.env.BETTER_AUTH_SECRET) {
	throw new Error("BETTER_AUTH_SECRET environment variable is required");
}

export const auth = betterAuth({
	database: new Pool({
		connectionString: process.env.DATABASE_URL,
	}),
	advanced: {
		database: {
			generateId: () => crypto.randomUUID(),
		},
	},
	secret: process.env.BETTER_AUTH_SECRET,

	rateLimit: {
		enabled: true,
		window: 60, // 60 seconds
		max: 100, // 100 requests per window
		customStorage: {
			get: async (key) => {
				try {
					const redis = await connectRedis();
					if (!redis) return null;

					const data = await redis.get(`rate_limit:${key}`);
					return data ? JSON.parse(data.toString()) : null;
				} catch {
					return null;
				}
			},
			set: async (key, value) => {
				try {
					const redis = await connectRedis();
					if (!redis) return;

					// Set TTL to match the longest rate limit window to ensure data persists
					// Better Auth will handle the sliding window logic internally
					const ttl = 240; // Match the longest window (request-password-reset: 180s + buffer)
					await redis.setEx(`rate_limit:${key}`, ttl, JSON.stringify(value));
				} catch {
					// Silently handle Redis errors
				}
			},
		},
		customRules: {
			"/sign-in/email": {
				window: 60,
				max: 3,
			},
			"/two-factor/verify": {
				window: 10,
				max: 3,
			},
			"/reset-password": {
				window: 60,
				max: 2,
			},
			"/request-password-reset": {
				window: 180,
				max: 1,
			},
			"/sign-up/email": {
				window: 60,
				max: 1,
			},
		},
	},

	socialProviders: {
		google: {
			clientId: process.env.GOOGLE_CLIENT_ID as string,
			clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
			accessType: "offline",
			prompt: "select_account consent",
		},
	},

	account: {
		accountLinking: {
			enabled: true,
		},
	},
	trustedOrigins: [
		process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000"
	],

	emailAndPassword: {
		enabled: true,
		requireEmailVerification: true,
		revokeSessionsOnPasswordReset: true,
		minPasswordLength: 6,
		resetPasswordTokenExpiresIn: 3600,
		password: {
			hash: async (plain) => {
				const salt = await bcrypt.genSalt(10);
				return bcrypt.hash(plain, salt);
			},
			verify: async ({ hash, password: plain }) => {
				return bcrypt.compare(plain, hash);
			},
		},
		
		onPasswordReset: async ({ user }) => {
			try {
				const userWithTenant = user as typeof user & {
					tenantId?: string;
				};
				if (userWithTenant.tenantId) {
					await deleteUserCache(user.id, userWithTenant.tenantId);
				}
			} catch (error) {
				console.error("Error clearing user cache on password reset:", error);
			}
		},
	},

	emailVerification: {
		sendOnSignUp: true,
		autoSignInAfterVerification: true,
		callbackURL: "/dashboard",
	},

	session: {
		expiresIn: 60 * 60 * 24 * 7, // 7 days
		updateAge: 60 * 60 * 24, // 24 hours
		cookieCache: {
			enabled: true,
			maxAge: 60 * 60, // 1 hour
		},
	},

	user: {
		additionalFields: {
			tenantId: {
				type: "string", // Keep as string since UUIDs are stored as text in JS
				required: false,
				input: false, // Don't include in forms by default
			},
		},
	},

	plugins: [
		nextCookies(),
		admin(),
		lastLoginMethod({
			maxAge: 60 * 60 * 24 * 30, // 30 days
		}),
		twoFactor({
			issuer: "Company",
			skipVerificationOnEnable: false,
			totpOptions: {
				digits: 6,
				period: 30,
			},
			backupCodeOptions: {
				amount: 10,
				length: 10,
			},
		}),
		passkey({
			rpID: process.env.NODE_ENV === "production" ? "company.com" : "localhost",
			rpName: "Company - Purchase Orders",
			origin:
				process.env.NODE_ENV === "production"
					? (process.env.NEXT_PUBLIC_APP_URL || "https://company.com").replace(/\/$/, "")
					: [
							"http://localhost:3000",
							"https://periodic-cap-beijing-cab.trycloudflare.com",
						],
			authenticatorSelection: {
				authenticatorAttachment: undefined, // Allow both platform and cross-platform
				residentKey: "preferred",
				userVerification: "preferred",
			},
		}),
		appInvite({
			sendInvitationEmail: async (data) => {
				const baseUrl =
					process.env.NODE_ENV === "production"
						? process.env.NEXT_PUBLIC_APP_URL || "https://company.com"
						: "http://localhost:3000";
				const inviteLink = `${baseUrl}/auth/accept-invitation?id=${data.id}`;
				await resend.emails.send({
					from: "Company Software <invitaciones@contacto.company.com>",
					to: data.email,
					subject: "Invitación a Company",
					react: AppInvitationEmail({
						name: data.name,
						email: data.email,
						invitedByEmail: data.inviter.email,
						inviteLink,
					}),
				});
			},
			invitationExpiresIn: null, // Never expire
			autoSignIn: false,
			cleanupExpiredInvitations: true,
			verifyEmailOnAccept: true,
			resendExistingInvite: true,
		}),
	],
});

export type Session = typeof auth.$Infer.Session;

Additional context

No response

Originally created by @RVP97 on GitHub (Dec 16, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Upgrade from 1.4.6 to 1.4.7 and try to create a new passkey. It will throw following error ERROR [Better Auth]: Failed to verify registration error: invalid input syntax for type uuid: "4TnQOJFeOfSaKbChINuNHDObycZ7siXh" at ignore-listed frames { length: 164, severity: 'ERROR', code: '22P02', detail: undefined, hint: undefined, position: undefined, internalPosition: undefined, internalQuery: undefined, where: "unnamed portal parameter $1 = '...'", schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'uuid.c', line: '141', routine: 'string_to_uuid' } ### Current vs. Expected behavior It should successfully create passkey. Right now, it gives out error, inserts into db put does not work if I try to sign in. ### What version of Better Auth are you using? 1.4.7 ### System info ```bash ❯ npx @better-auth/cli info --json { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.0.0: Mon Aug 25 21:17:51 PDT 2025; root:xnu-12377.1.9~3/RELEASE_ARM64_T6000", "release": "25.0.0", "cpuCount": 10, "cpuModel": "Apple M1 Pro", "totalMemory": "16.00 GB", "freeMemory": "0.16 GB" }, "node": { "version": "v22.12.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.5.2" }, "frameworks": [ { "name": "next", "version": "16.0.10" }, { "name": "react", "version": "19.2.3" } ], "databases": [ { "name": "pg", "version": "^8.16.3" }, { "name": "postgres", "version": "^3.4.7" } ], "betterAuth": { "version": "^1.4.7", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Other ### Auth config (if applicable) ```typescript import { passkey } from "@better-auth/passkey"; import { appInvite } from "@better-auth-extended/app-invite"; import bcrypt from "bcryptjs"; import { betterAuth } from "better-auth"; import { nextCookies } from "better-auth/next-js"; import { admin, lastLoginMethod, twoFactor } from "better-auth/plugins"; import { Pool } from "pg"; import { Resend } from "resend"; import AppInvitationEmail from "@/components/emails/app-invitation"; import ConfirmEmail from "@/components/emails/confirm-email"; import PasswordResetEmail from "@/components/emails/password-reset"; import { deleteUserCache } from "@/lib/redis/cache-utils"; import { connectRedis } from "@/lib/redis/client"; const resend = new Resend(process.env.RESEND_API_KEY); if (!process.env.DATABASE_URL) { throw new Error("DATABASE_URL environment variable is required"); } if (!process.env.BETTER_AUTH_SECRET) { throw new Error("BETTER_AUTH_SECRET environment variable is required"); } export const auth = betterAuth({ database: new Pool({ connectionString: process.env.DATABASE_URL, }), advanced: { database: { generateId: () => crypto.randomUUID(), }, }, secret: process.env.BETTER_AUTH_SECRET, rateLimit: { enabled: true, window: 60, // 60 seconds max: 100, // 100 requests per window customStorage: { get: async (key) => { try { const redis = await connectRedis(); if (!redis) return null; const data = await redis.get(`rate_limit:${key}`); return data ? JSON.parse(data.toString()) : null; } catch { return null; } }, set: async (key, value) => { try { const redis = await connectRedis(); if (!redis) return; // Set TTL to match the longest rate limit window to ensure data persists // Better Auth will handle the sliding window logic internally const ttl = 240; // Match the longest window (request-password-reset: 180s + buffer) await redis.setEx(`rate_limit:${key}`, ttl, JSON.stringify(value)); } catch { // Silently handle Redis errors } }, }, customRules: { "/sign-in/email": { window: 60, max: 3, }, "/two-factor/verify": { window: 10, max: 3, }, "/reset-password": { window: 60, max: 2, }, "/request-password-reset": { window: 180, max: 1, }, "/sign-up/email": { window: 60, max: 1, }, }, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, accessType: "offline", prompt: "select_account consent", }, }, account: { accountLinking: { enabled: true, }, }, trustedOrigins: [ process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000" ], emailAndPassword: { enabled: true, requireEmailVerification: true, revokeSessionsOnPasswordReset: true, minPasswordLength: 6, resetPasswordTokenExpiresIn: 3600, password: { hash: async (plain) => { const salt = await bcrypt.genSalt(10); return bcrypt.hash(plain, salt); }, verify: async ({ hash, password: plain }) => { return bcrypt.compare(plain, hash); }, }, onPasswordReset: async ({ user }) => { try { const userWithTenant = user as typeof user & { tenantId?: string; }; if (userWithTenant.tenantId) { await deleteUserCache(user.id, userWithTenant.tenantId); } } catch (error) { console.error("Error clearing user cache on password reset:", error); } }, }, emailVerification: { sendOnSignUp: true, autoSignInAfterVerification: true, callbackURL: "/dashboard", }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, // 24 hours cookieCache: { enabled: true, maxAge: 60 * 60, // 1 hour }, }, user: { additionalFields: { tenantId: { type: "string", // Keep as string since UUIDs are stored as text in JS required: false, input: false, // Don't include in forms by default }, }, }, plugins: [ nextCookies(), admin(), lastLoginMethod({ maxAge: 60 * 60 * 24 * 30, // 30 days }), twoFactor({ issuer: "Company", skipVerificationOnEnable: false, totpOptions: { digits: 6, period: 30, }, backupCodeOptions: { amount: 10, length: 10, }, }), passkey({ rpID: process.env.NODE_ENV === "production" ? "company.com" : "localhost", rpName: "Company - Purchase Orders", origin: process.env.NODE_ENV === "production" ? (process.env.NEXT_PUBLIC_APP_URL || "https://company.com").replace(/\/$/, "") : [ "http://localhost:3000", "https://periodic-cap-beijing-cab.trycloudflare.com", ], authenticatorSelection: { authenticatorAttachment: undefined, // Allow both platform and cross-platform residentKey: "preferred", userVerification: "preferred", }, }), appInvite({ sendInvitationEmail: async (data) => { const baseUrl = process.env.NODE_ENV === "production" ? process.env.NEXT_PUBLIC_APP_URL || "https://company.com" : "http://localhost:3000"; const inviteLink = `${baseUrl}/auth/accept-invitation?id=${data.id}`; await resend.emails.send({ from: "Company Software <invitaciones@contacto.company.com>", to: data.email, subject: "Invitación a Company", react: AppInvitationEmail({ name: data.name, email: data.email, invitedByEmail: data.inviter.email, inviteLink, }), }); }, invitationExpiresIn: null, // Never expire autoSignIn: false, cleanupExpiredInvitations: true, verifyEmailOnAccept: true, resendExistingInvite: true, }), ], }); export type Session = typeof auth.$Infer.Session; ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 10:02:11 -05:00
Author
Owner

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

Hi there, thanks for reporting this passkey issue with version 1.4.7. The error indicates that there’s a problem converting a generated string into a UUID (the error “invalid input syntax for type uuid” suggests that a value that isn’t a valid UUID is being passed to the database). A few troubleshooting steps to consider:

• Verify that your database columns expecting UUIDs are correctly configured and that any new UUID values generated (for example via crypto.randomUUID() in your configuration) are in the proper format.

• Check the passkey internals to see if the registration process might be using an older format or inadvertently generating a non-UUID value. It could be that the update from 1.4.6 to 1.4.7 introduced a change in how IDs are generated or validated.

• Review your custom advanced.database.generateId setting to ensure it returns a valid UUID string—if it’s modified or overridden elsewhere, it might be causing the issue.

If these steps don’t resolve the problem, you might want to provide additional logging or context for the passkey creation process. Tag @bekacru and @ping__ if needed for deeper investigation.

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

What other details about your setup can you share to help narrow down the issue?

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Dec 16, 2025): Hi there, thanks for reporting this passkey issue with version 1.4.7. The error indicates that there’s a problem converting a generated string into a UUID (the error “invalid input syntax for type uuid” suggests that a value that isn’t a valid UUID is being passed to the database). A few troubleshooting steps to consider: • Verify that your database columns expecting UUIDs are correctly configured and that any new UUID values generated (for example via crypto.randomUUID() in your configuration) are in the proper format. • Check the passkey internals to see if the registration process might be using an older format or inadvertently generating a non-UUID value. It could be that the update from 1.4.6 to 1.4.7 introduced a change in how IDs are generated or validated. • Review your custom advanced.database.generateId setting to ensure it returns a valid UUID string—if it’s modified or overridden elsewhere, it might be causing the issue. If these steps don’t resolve the problem, you might want to provide additional logging or context for the passkey creation process. Tag @bekacru and @ping__ if needed for deeper investigation. tag @better-auth-agent if you would like an answer from the Agent What other details about your setup can you share to help narrow down the issue? _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@dosubot[bot] commented on GitHub (Dec 16, 2025):

This is a regression in 1.4.7: the passkey registration flow now generates a random 32-character string for certain IDs (like challenge or verification values), but your database expects a UUID, so it throws an "invalid input syntax for type uuid" error when it tries to insert a non-UUID string like "4TnQOJFeOfSaKbChINuNHDObycZ7siXh" (details & code).

To work around this until a fix lands, update your generateId function in the Better Auth config to always return a valid UUID (e.g., crypto.randomUUID()) for any model/table where the database expects a UUID. If you have mixed ID types (like integer IDs for users and UUIDs for passkeys), you can do:

advanced: {
  database: {
    generateId: ({ model }) => {
      if (model === "user") return undefined; // Let DB auto-generate for users (e.g., serial/integer)
      return crypto.randomUUID(); // UUID for everything else
    }
  }
}

This will let the DB handle user IDs and ensure UUIDs for passkeys and other tables that require them (see workaround).

If you have custom adapters or plugins, double-check that they don't expect a different ID format. Keep an eye out for an upstream patch to 1.4.x that addresses this regression. If you need help with a specific config or edge case, let me know!

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

@dosubot[bot] commented on GitHub (Dec 16, 2025): <!-- Answer --> This is a regression in 1.4.7: the passkey registration flow now generates a random 32-character string for certain IDs (like challenge or verification values), but your database expects a UUID, so it throws an "invalid input syntax for type uuid" error when it tries to insert a non-UUID string like `"4TnQOJFeOfSaKbChINuNHDObycZ7siXh"` ([details & code](https://github.com/better-auth/better-auth/blob/1c671650504b31626c7e12082b73b8e7832b7a5d/packages/passkey/src/routes.ts#L187-L517)). To work around this until a fix lands, update your `generateId` function in the Better Auth config to always return a valid UUID (e.g., `crypto.randomUUID()`) for any model/table where the database expects a UUID. If you have mixed ID types (like integer IDs for users and UUIDs for passkeys), you can do: ```typescript advanced: { database: { generateId: ({ model }) => { if (model === "user") return undefined; // Let DB auto-generate for users (e.g., serial/integer) return crypto.randomUUID(); // UUID for everything else } } } ``` This will let the DB handle user IDs and ensure UUIDs for passkeys and other tables that require them ([see workaround](https://github.com/better-auth/better-auth/issues/5081)). If you have custom adapters or plugins, double-check that they don't expect a different ID format. Keep an eye out for an upstream patch to 1.4.x that addresses this regression. If you need help with a specific config or edge case, let me know! <!-- 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/4239c5c0-3841-4433-9d2f-71264f2c8379?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/4239c5c0-3841-4433-9d2f-71264f2c8379?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/4239c5c0-3841-4433-9d2f-71264f2c8379?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/4239c5c0-3841-4433-9d2f-71264f2c8379?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/4239c5c0-3841-4433-9d2f-71264f2c8379?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/4239c5c0-3841-4433-9d2f-71264f2c8379?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/4239c5c0-3841-4433-9d2f-71264f2c8379?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=This%20is%20a%20regression%20in%201.4.7%3A%20the%20passkey%20registration%20flow%20now%20generates%20a%20random%2032-character%20string%20for%20certain%20IDs%20%28like%20challenge%20or%20verification%20values%29%2C%20but%20your%20database%20expects%20a%20UUID%2C%20so%20it%20throws%20an%20%22invalid%20input%20syntax%20for%20type%20uuid%22%20error%20when%20it%20tries%20to%20insert%20a%20non-UUID%20string%20like%20%60%224TnQOJFeOfSaKbChINuNHDObycZ7siXh%22%60%C2%A0%28%5Bdetails%20%26%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/1c671650504b31626c7e12082b73b8e7832b7a5d/packages/passkey/src/routes.ts%23L187-L517%29%29.%0A%0ATo%20work%20around%20this%20until%20a%20fix%20lands%2C%20update%20your%20%60generateId%60%20function%20in%20the%20Better%20Auth%20config%20to%20always%20return%20a%20valid%20UUID%20%28e.g.%2C%20%60crypto.randomUUID%28%29%60%29%20for%20any%20model/table%20where%20the%20database%20expects%20a%20UUID.%20If%20you%20have%20mixed%20ID%20types%20%28like%20integer%20IDs%20for%20users%20and%20UUIDs%20for%20passkeys%29%2C%20you%20can%20do%3A%0A%0A%60%60%60typescript%0Aadvanced%3A%20%7B%0A%20%20database%3A%20%7B%0A%20%20%20%20generateId%3A%20%28%7B%20model%20%7D%29%20%3D%3E%20%7B%0A%20%20%20%20%20%20if%20%28model%20%3D%3D%3D%20%22user%22%29%20return%20undefined%3B%20//%20Let%20DB%20auto-generate%20for%20users%20%28e.g.%2C%20serial/integer%29%0A%20%20%20%20%20%20return%20crypto.randomUUID%28%29%3B%20//%20UUID%20for%20everything%20else%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0AThis%20will%20let%20the%20DB%20handle%20user%20IDs%20and%20ensure%20UUIDs%20for%20passkeys%20and%20other%20tables%20that%20require%20them%C2%A0%28%5Bsee%20workaround%5D%28https%3A//github.com/better-auth/better-auth/issues/5081%29%29.%0A%0AIf%20you%20have%20custom%20adapters%20or%20plugins%2C%20double-check%20that%20they%20don%27t%20expect%20a%20different%20ID%20format.%20Keep%20an%20eye%20out%20for%20an%20upstream%20patch%20to%201.4.x%20that%20addresses%20this%20regression.%20If%20you%20need%20help%20with%20a%20specific%20config%20or%20edge%20case%2C%20let%20me%20know%21)&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/6802)
Author
Owner

@RVP97 commented on GitHub (Dec 16, 2025):

@dosu hey, just tried

 advanced: {
		database: {
			generateId: (options) => {
				if (options.model === "passkey") {
					return false; // Let the DB handle UUID generation
				}
				return crypto.randomUUID(); // UUIDs for other tables
			},
		},
	},

but it returns same error as before

ERROR [Better Auth]: Failed to verify registration error: invalid input syntax for type uuid: "ReY5XOKs3rHWJvQ5GYpXvD95rq8KW7KF"
at ignore-listed frames {
length: 164,
severity: 'ERROR',
code: '22P02',
detail: undefined,
hint: undefined,
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: "unnamed portal parameter $1 = '...'",
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'uuid.c',
line: '141',
routine: 'string_to_uuid'
}

@RVP97 commented on GitHub (Dec 16, 2025): @dosu hey, just tried ``` advanced: { database: { generateId: (options) => { if (options.model === "passkey") { return false; // Let the DB handle UUID generation } return crypto.randomUUID(); // UUIDs for other tables }, }, }, ``` but it returns same error as before ERROR [Better Auth]: Failed to verify registration error: invalid input syntax for type uuid: "ReY5XOKs3rHWJvQ5GYpXvD95rq8KW7KF" at ignore-listed frames { length: 164, severity: 'ERROR', code: '22P02', detail: undefined, hint: undefined, position: undefined, internalPosition: undefined, internalQuery: undefined, where: "unnamed portal parameter $1 = '...'", schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'uuid.c', line: '141', routine: 'string_to_uuid' }
Author
Owner

@dosubot[bot] commented on GitHub (Dec 16, 2025):

The error persists because the passkey registration flow in Better Auth 1.4.7 generates a 32-character random string for the challenge identifier using a direct helper, not your generateId override. This string is inserted into a column that expects a UUID, causing the "invalid input syntax for type uuid" error. Changing generateId in your config only affects model-level IDs, not these challenge/verification identifiers.

To work around this, you can either (1) alter your verification values table so the identifier column is text instead of UUID, or (2) monkey-patch the generateId(32) call in node_modules/@better-auth/passkey to use crypto.randomUUID() for now. Watch for an upstream fix that aligns challenge ID generation with your config. More details: see code reference.

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

@dosubot[bot] commented on GitHub (Dec 16, 2025): <!-- Answer --> The error persists because the passkey registration flow in Better Auth 1.4.7 generates a 32-character random string for the challenge identifier using a direct helper, not your generateId override. This string is inserted into a column that expects a UUID, causing the "invalid input syntax for type uuid" error. Changing generateId in your config only affects model-level IDs, not these challenge/verification identifiers. To work around this, you can either (1) alter your verification values table so the identifier column is text instead of UUID, or (2) monkey-patch the generateId(32) call in node_modules/@better-auth/passkey to use crypto.randomUUID() for now. Watch for an upstream fix that aligns challenge ID generation with your config. More details: [see code reference](https://github.com/better-auth/better-auth/blob/1c671650504b31626c7e12082b73b8e7832b7a5d/packages/passkey/src/routes.ts#L215-L508). <!-- 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/054e78ae-164a-4b73-bf9d-201fb716ea49?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/054e78ae-164a-4b73-bf9d-201fb716ea49?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/054e78ae-164a-4b73-bf9d-201fb716ea49?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/054e78ae-164a-4b73-bf9d-201fb716ea49?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/054e78ae-164a-4b73-bf9d-201fb716ea49?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/054e78ae-164a-4b73-bf9d-201fb716ea49?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/054e78ae-164a-4b73-bf9d-201fb716ea49?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%20persists%20because%20the%20passkey%20registration%20flow%20in%20Better%20Auth%201.4.7%20generates%20a%2032-character%20random%20string%20for%20the%20challenge%20identifier%20using%20a%20direct%20helper%2C%20not%20your%20generateId%20override.%20This%20string%20is%20inserted%20into%20a%20column%20that%20expects%20a%20UUID%2C%20causing%20the%20%22invalid%20input%20syntax%20for%20type%20uuid%22%20error.%20Changing%20generateId%20in%20your%20config%20only%20affects%20model-level%20IDs%2C%20not%20these%20challenge/verification%20identifiers.%0A%0ATo%20work%20around%20this%2C%20you%20can%20either%20%281%29%20alter%20your%20verification%20values%20table%20so%20the%20identifier%20column%20is%20text%20instead%20of%20UUID%2C%20or%20%282%29%20monkey-patch%20the%20generateId%2832%29%20call%20in%20node_modules/%40better-auth/passkey%20to%20use%20crypto.randomUUID%28%29%20for%20now.%20Watch%20for%20an%20upstream%20fix%20that%20aligns%20challenge%20ID%20generation%20with%20your%20config.%20More%20details%3A%20%5Bsee%20code%20reference%5D%28https%3A//github.com/better-auth/better-auth/blob/1c671650504b31626c7e12082b73b8e7832b7a5d/packages/passkey/src/routes.ts%23L215-L508%29.)&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/6802)
Author
Owner

@RVP97 commented on GitHub (Dec 16, 2025):

Is this expected to be released soon?

@RVP97 commented on GitHub (Dec 16, 2025): Is this expected to be released soon?
Author
Owner

@XavierGeerinck commented on GitHub (Dec 16, 2025):

I just hit the same problem, a non-UUID IDs is created for the verification table that causes an invalid input syntax.

Update: would propose the issue title: passkey plugin not respecting uuid id generation

@XavierGeerinck commented on GitHub (Dec 16, 2025): I just hit the same problem, a non-UUID IDs is created for the verification table that causes an invalid input syntax. Update: would propose the issue title: `passkey plugin not respecting uuid id generation`
Author
Owner

@bytaesu commented on GitHub (Dec 17, 2025):

Hello @XavierGeerinck @RVP97,

Could you try this version and let me know if the issue is resolved? PR versions

npm i https://pkg.pr.new/better-auth/better-auth@6821

npm i https://pkg.pr.new/better-auth/better-auth/@better-auth/passkey@6821
@bytaesu commented on GitHub (Dec 17, 2025): Hello @XavierGeerinck @RVP97, Could you try this version and let me know if the issue is resolved? [PR versions](https://github.com/better-auth/better-auth/pull/6821#issuecomment-3664828327) ``` npm i https://pkg.pr.new/better-auth/better-auth@6821 npm i https://pkg.pr.new/better-auth/better-auth/@better-auth/passkey@6821 ```
Author
Owner

@RVP97 commented on GitHub (Dec 17, 2025):

Hey! I just tested it and it did work perfectly. Thank you

@RVP97 commented on GitHub (Dec 17, 2025): Hey! I just tested it and it did work perfectly. Thank you
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2548