mem0ai/mem0 · error · APIError
Bad request to ${path}: ${detail}
Error message
Bad request to ${path}: ${detail} What it means
POST /auth/login found the user by email but bcrypt verification of the submitted password against the stored hash failed, yielding the same generic 401 as a missing account. Only the exact original password verifies; there is no recovery from the API itself beyond admin-driven reset.
Source
Thrown at integrations/openclaw/backend/platform.ts:74
const resp = await fetch(url, fetchOpts);
if (resp.status === 401) {
throw new AuthError();
}
if (resp.status === 404) {
throw new NotFoundError(path);
}
if (resp.status === 400) {
let detail: string;
try {
const body = (await resp.json()) as Record<string, unknown>;
detail =
((body.detail ?? body.message ?? JSON.stringify(body)) as string) ??
resp.statusText;
} catch {
detail = resp.statusText;
}
throw new APIError(path, detail);
}
if (!resp.ok) {
let detail: string = resp.statusText;
try {
const body = (await resp.json()) as Record<string, unknown>;
detail = (body.detail ?? body.message ?? resp.statusText) as string;
} catch {
/* ignore */
}
throw new Error(`HTTP ${resp.status}: ${detail}`);
}
if (resp.status === 204) {
return {};
}
return resp.json();
}
async add(View on GitHub (pinned to 001c235229)
Solutions
- Re-enter the correct password carefully (watch for caps-lock/whitespace); .strip() shell-provided values.
- If forgotten and another admin exists, have the admin reset it via user management; if it is the only admin, an operator with DB access can set a new hash via the server's hash_password utility.
- Update stored secrets/CI variables after any credential rotation and test with a manual login before retrying the pipeline.
Example fix
# before password=$(cat pw.txt) # may include trailing newline -> 401 login(email, password) # after password=$(cat pw.txt | tr -d '\n') login(email, password)
Defensive patterns
Strategy: validation
Validate before calling
def validate_login_input(password: str) -> str:
pw = password.strip()
if len(pw) < 8:
raise ValueError("Password shorter than the server minimum of 8; likely truncated or wrong field")
return pw Type guard
def is_credential_candidate(password: str | None) -> bool:
return isinstance(password, str) and len(password.strip()) >= 8 Try / catch
if resp.status_code == 401 and "Invalid email or password" in resp.text:
if attempt < MAX_ATTEMPTS:
password = prompt_fresh_password() # re-collect; never retry the same value blindly
else:
raise CredentialsError("Password rejected; rotate via admin reset") Prevention
- Strip whitespace/newlines from secret values read from files or env.
- Update CI/secret-manager entries immediately after password rotations.
- Prefer API keys over shared passwords for automation.
When it happens
Trigger: Wrong password (typo, stale credential, changed password); password from a different environment's account; trailing whitespace introduced when pasting the password; credentials rotated by an admin after they were stored in the client.
Common situations: CI secrets holding an old password after an admin reset; password managers auto-filling outdated entries; local dev password differing from the seeded one; copy/paste adding a trailing newline in shell scripts.
Related errors
- Resource not found: ${path}
- Authentication failed. Your API key may be invalid or expire
- Resource not found: ${path}
- Bad request to ${path}: ${detail}
- Either memoryId or --all is required
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/10e8aa3647698eef.
Report an issue: GitHub.