nextauthjs/next-auth · error · CredentialsSignin
CredentialsSignin
Error message
CredentialsSignin
What it means
CredentialsSignin is thrown during a credentials provider sign-in when the provider's `authorize` callback resolves to a falsy user (null/undefined). Auth.js treats a falsy return as 'these credentials did not match any user' and aborts the callback flow, which surfaces to the client as the CredentialsSignin error code. It exists so applications can distinguish failed credential checks from other route errors.
Source
Thrown at packages/core/src/lib/actions/callback/index.ts:339
}
// Callback URL is already verified at this point, so safe to use if specified
return { redirect: callbackUrl, cookies }
} else if (provider.type === "credentials" && method === "POST") {
const credentials = body ?? {}
// TODO: Forward the original request as is, instead of reconstructing it
Object.entries(query ?? {}).forEach(([k, v]) =>
url.searchParams.set(k, v)
)
const userFromAuthorize = await provider.authorize(
credentials,
// prettier-ignore
new Request(url, { headers, method, body: JSON.stringify(body) })
)
const user = userFromAuthorize
if (!user) throw new CredentialsSignin()
else user.id = user.id?.toString() ?? crypto.randomUUID()
const account = {
providerAccountId: user.id,
type: "credentials",
provider: provider.id,
} satisfies Account
const redirect = await handleAuthorized(
{ user, account, credentials },
options
)
if (redirect) return { redirect, cookies }
const defaultToken = {
name: user.name,
email: user.email,
picture: user.image,View on GitHub (pinned to a1a16a5a77)
Solutions
- Check that `authorize()` explicitly returns the user object when credentials are valid, and null only on failure
- Verify the credential comparison (e.g. bcrypt.compare) is awaited and actually checked before returning the user
- Confirm the user lookup uses the correct identifier field and that the user exists in the database
- On the client, handle the CredentialsSignin error code (fetch to /callback/credentials or signIn with redirect:false) to show a 'wrong credentials' message
Example fix
// before
authorize: async (credentials) => {
const user = await getUser(credentials.email)
bcrypt.compare(credentials.password, user.passwordHash) // result ignored
return user
}
// after
authorize: async (credentials) => {
const user = await getUser(credentials?.email)
if (!user) return null
const ok = await bcrypt.compare(credentials.password, user.passwordHash)
if (!ok) return null
return user
} Defensive patterns
Strategy: try-catch
Validate before calling
// client-side guard before/at sign-in
const creds = { email, password }
if (!creds.email || !creds.password) throw new Error("Missing credentials") Type guard
function hasCredentials(c: unknown): c is { email: string; password: string } {
return typeof c === "object" && c !== null &&
typeof (c as any).email === "string" && typeof (c as any).password === "string"
} Try / catch
const res = await signIn("credentials", { redirect: false, email, password })
if (res?.error === "CredentialsSignin") {
// show 'invalid username or password'
} Prevention
- Always return null explicitly on failed auth in authorize(), and the user object on success
- Await every async credential comparison before returning
- Handle the CredentialsSignin error code on the client rather than crashing
- Unit-test authorize() with valid, invalid, and missing inputs
When it happens
Trigger: A POST to /api/auth/callback/credentials where the credentials provider's `authorize()` returns null or undefined — e.g. the username/password lookup found no matching user, a password comparison (bcrypt/argon2) failed, or the developer forgot to return the user object on success.
Common situations: Wrong password entered by the user; `authorize` queries the DB with the wrong field (email vs username); missing await on the DB lookup so a promise resolves unexpectedly; authorize returns an object without running credential verification (in dev prototypes); env vars for the database not set so the lookup returns nothing.
Related errors
- [updateSession] Failed to fetch updated session
- Object is nullish
- User not found
- Account not found
- Session not found
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/79b357b13f4b60a1.
Report an issue: GitHub.