{"record":{"id":"f7454fe0ab9a371a","repo":"mastra-ai/mastra","slug":"invalid-email-or-password","errorCode":null,"errorMessage":"Invalid email or password","messagePattern":"Invalid email or password","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"auth/better-auth/src/index.ts","lineNumber":765,"sourceCode":"  async signIn(email: string, password: string, request: Request): Promise<CredentialsResult<EEUser>> {\n    const headers = request?.headers ?? new Headers();\n\n    // Use asResponse: true to get the full response with Set-Cookie headers\n    const response = await this.auth.api.signInEmail({\n      body: { email, password },\n      headers,\n      asResponse: true,\n    });\n\n    if (!response.ok) {\n      const errorData = (await response.json().catch(() => ({}))) as { message?: string };\n      throw new Error(errorData.message || 'Invalid email or password');\n    }\n\n    const result = (await response.json()) as { user?: User; token?: string | null };\n\n    if (!result?.user) {\n      throw new Error('Invalid email or password');\n    }\n\n    // Extract Set-Cookie headers from Better Auth response\n    const cookies: string[] = [];\n    const setCookieHeader = response.headers.get('set-cookie');\n    if (setCookieHeader) {\n      // Split multiple cookies (they may be comma-separated or in multiple headers)\n      cookies.push(...setCookieHeader.split(/,(?=\\s*\\w+=)/));\n    }\n\n    return {\n      user: mapBetterAuthUserToEEUser(result.user),\n      token: result.token ?? undefined,\n      cookies,\n    };\n  }\n\n  /**","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/auth/better-auth/src/index.ts#L747-L783","documentation":"After a sign-in request that returned OK, signIn() checks that the parsed JSON body contains result.user. If Better Auth returned a 2xx response without a user object, the provider throws 'Invalid email or password'. This is a defensive fallback for malformed or empty success responses.","triggerScenarios":"signIn({ email, password }) where response.ok === true but `result?.user` is falsy — e.g. body shape changed across better-auth versions, empty body, or a 200 with only a token/error field instead of a user.","commonSituations":"better-auth version drift where signInEmail's success payload shape differs from the expected { user, token }; proxy/CDN returning an empty 200; interceptors swallowing the response body.","solutions":["Check the installed better-auth version and its signInEmail response shape; align with the version this provider expects.","Log the raw response body to see what the server actually returned on success.","Fall back to the sign-in flow's error path: retry signIn with corrected credentials in case the server returned 200 for a non-authenticated session."],"exampleFix":"// before: expecting { user } but better-auth v1.x returns different shape\nconst result = await auth.signIn({ email, password });\n\n// after: pin/upgrade better-auth to the version whose signInEmail returns { user, token }\n// package.json: \"better-auth\": \"<version compatible with @mastra/auth-better-auth>\"","handlingStrategy":"type-guard","validationCode":"const res = await providerSignInResponse;\nif (res.ok) {\n  const body = await res.json();\n  if (!body?.user) console.warn('signIn returned 2xx without user; check better-auth version compatibility');\n}","typeGuard":"function hasUser(r: unknown): r is { user: User; token?: string | null } {\n  return typeof r === 'object' && r !== null && 'user' in r && typeof (r as { user: unknown }).user === 'object';\n}","tryCatchPattern":"try {\n  const result = await provider.signIn({ email, password });\n  if (!hasUser(result)) throw new Error('Sign-in succeeded but no user was returned');\n} catch (e) {\n  if (e instanceof Error && e.message === 'Invalid email or password') {\n    console.error('Unexpected 2xx-without-user from better-auth; verify better-auth version');\n  }\n  throw e;\n}","preventionTips":["Pin better-auth to a version within @mastra/auth-better-auth's supported range.","Add a contract test asserting signIn() returns a user for valid credentials.","Watch for proxies/interceptors that strip or reshape response bodies."],"tags":["authentication","response-shape","better-auth","version-compat"],"backgroundTag":"unexpected-response-shape","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}