mastra-ai/mastra · error
Invalid email or password
Error message
Invalid email or password
What it means
Thrown in signIn() when the Neon Auth sign-in API responds with a non-OK status. The library first tries to surface the server-provided message from the error body; if the body has no message (or the body isn't JSON), it falls back to this generic message. It deliberately hides the real cause to avoid leaking whether the account exists.
Source
Thrown at auth/neon/src/index.ts:297
return true;
}
// ── ICredentialsProvider ──
async signIn(email: string, password: string, request: Request): Promise<CredentialsResult<EEUser>> {
const response = await fetch(`${this.baseUrl}/auth/sign-in/email`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(request?.headers ? Object.fromEntries(request.headers.entries()) : {}),
},
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
const errorData = (await response.json().catch(() => ({}))) as { message?: string };
throw new Error(errorData.message || 'Invalid email or password');
}
const result = (await response.json()) as { user?: NeonSessionResponse['user']; token?: string | null };
if (!result?.user) {
throw new Error('Invalid email or password');
}
const cookies = parseCookies(response);
return {
user: mapNeonUserToEEUser(result.user),
token: result.token ?? undefined,
cookies,
};
}
async signUp(View on GitHub (pinned to 75dd419e61)
Solutions
- Double-check the email and password being passed
- Register the user first (sign-up) before calling signIn
- Log the underlying HTTP response (or add temporary logging) to see the server's actual status/body — a 502/503 indicates infrastructure, not bad credentials
- If a custom error message is expected, ensure the Neon Auth error responses include a 'message' field
Example fix
// before
await auth.signIn({ email: userInput.email, password: userInput.password });
// after
if (!userExists(email)) await auth.signUp({ email, password });
await auth.signIn({ email, password }); Defensive patterns
Strategy: try-catch
Validate before calling
function assertSignInInput(email: unknown, password: unknown): asserts email is string {
if (typeof email !== 'string' || !email.includes('@') || email.length === 0) {
throw new Error('A valid email is required');
}
if (typeof password !== 'string' || password.length === 0) {
throw new Error('A password is required');
}
} Type guard
function isAuthError(err: unknown): err is Error & { message: string } {
return err instanceof Error && /invalid email or password/i.test(err.message);
} Try / catch
try {
const session = await auth.signIn({ email, password });
} catch (err) {
if (isAuthError(err)) {
showUserFriendlyError('Those credentials do not match an account'); // don't leak which field failed
} else {
throw err; // infrastructure error — surface it
}
} Prevention
- Show a generic message to end users; log server-side details separately
- Ensure users complete sign-up before attempting sign-in
- If errors persist despite correct credentials, check whether the response is actually an HTML error page (proxy/network issue)
- Add rate limiting to prevent credential stuffing against signIn
When it happens
Trigger: Calling auth.signIn({ email, password }) where the credentials are wrong, the user doesn't exist, the response body is not JSON, or the server returns an error without a 'message' field.
Common situations: Typos in email/password; user never signed up with Neon Auth; a reverse proxy returning an HTML 502 page (body parse fails, so the real cause is masked); Neon Auth API changed its error body shape.
Related errors
- Neon Auth base URL is required, please provide it in the opt
- Authentication failed / server-provided message
- Kimi For Coding credentials have an invalid device ID. Pleas
- No credentials
- Not logged in
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/79861bd4a826e651.
Report an issue: GitHub.