mastra-ai/mastra · error
${errorData.message || 'Invalid email or password'}
Error message
${errorData.message || 'Invalid email or password'} What it means
signIn() calls Better Auth's sign-in endpoint (via auth.api.signInEmail with asResponse: true). If the HTTP response is not OK, it tries to parse a JSON body for a `message` and throws that message, defaulting to 'Invalid email or password'. This is the provider surfacing the server-side rejection of the credential pair.
Source
Thrown at auth/better-auth/src/index.ts:759
* @param email - User email
* @param password - User password
* @param request - Incoming HTTP request
* @returns Result with user and session cookies
* @throws Error if credentials are invalid
*/
async signIn(email: string, password: string, request: Request): Promise<CredentialsResult<EEUser>> {
const headers = request?.headers ?? new Headers();
// Use asResponse: true to get the full response with Set-Cookie headers
const response = await this.auth.api.signInEmail({
body: { email, password },
headers,
asResponse: true,
});
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?: User; token?: string | null };
if (!result?.user) {
throw new Error('Invalid email or password');
}
// Extract Set-Cookie headers from Better Auth response
const cookies: string[] = [];
const setCookieHeader = response.headers.get('set-cookie');
if (setCookieHeader) {
// Split multiple cookies (they may be comma-separated or in multiple headers)
cookies.push(...setCookieHeader.split(/,(?=\s*\w+=)/));
}
return {
user: mapBetterAuthUserToEEUser(result.user),View on GitHub (pinned to 75dd419e61)
Solutions
- Verify the email/password combination is correct and the user exists in the Better Auth database the server is connected to.
- Surface the underlying errorData.message from the response body to pinpoint the actual server rejection (rate limit, disabled account, etc.).
- If the user is OAuth-only, use the appropriate OAuth sign-in flow instead of email/password.
- Confirm the server instance (auth option) points at the same database used at sign-up.
Example fix
// before: signing in against a fresh test DB with no such user
await auth.signIn({ email: 'dev@example.com', password: 'hunter2' }); // throws
// after: sign up first (or use seeded fixtures)
await auth.signUp({ email: 'dev@example.com', password: 'hunter2', name: 'Dev' });
await auth.signIn({ email: 'dev@example.com', password: 'hunter2' }); Defensive patterns
Strategy: try-catch
Validate before calling
function isValidSignInInput(input: { email: string; password: string }): boolean {
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(input.email) && input.password.length > 0;
} Type guard
function isInvalidCredentialsError(e: unknown): e is Error {
return e instanceof Error && (e.message === 'Invalid email or password' || /invalid|credential/i.test(e.message));
} Try / catch
try {
await provider.signIn({ email, password });
} catch (e) {
if (isInvalidCredentialsError(e)) {
return { ok: false, reason: 'bad-credentials' }; // do not leak which field was wrong
}
throw e;
} Prevention
- Return a generic 'invalid credentials' message to users; never reveal whether email or password was wrong.
- Seed test users before running sign-in flows in CI.
- Handle OAuth-only accounts with social sign-in rather than email/password.
- Add rate limiting/lockout handling around repeated failed sign-ins.
When it happens
Trigger: signIn({ email, password }) where auth.api.signInEmail returns response.ok === false — unknown email, wrong password, account without a password credential (OAuth-only), rate-limited or disabled account; errorData.message is used when the error body contains one.
Common situations: User typos credentials; user registered via social/OAuth so no password exists; test fixtures using a user never signed up in the test database; server misconfigured against a different database than where the user registered.
Related errors
- ${errorData.message || 'Failed to create account'}
- Invalid email or password
- Failed to create account
- Authentication failed / server-provided message
- VoiceCredentialError(entry.provider)
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/c9a40cfaedb791a3.
Report an issue: GitHub.