unslothai/unsloth · error · HTTPException
Password change required
Error message
Password change required
What it means
HTTP 403 raised when the authenticated user's record has must_change_password set, the request is not on an allowed password-change route, and the token is not a desktop token. It enforces a password-reset gate: until the user sets a new password, all other API access is refused.
Source
Thrown at studio/backend/auth/authentication.py:299
record = get_user_and_secret(subject)
if record is None:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Invalid or expired token",
)
_salt, _pwd_hash, jwt_secret, must_change_password = record
try:
payload = jwt.decode(token, jwt_secret, algorithms = [ALGORITHM])
if payload.get("sub") != subject:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Invalid token payload",
)
is_desktop = payload.get("desktop") is True
if must_change_password and not allow_password_change and not is_desktop:
raise HTTPException(
status_code = status.HTTP_403_FORBIDDEN,
detail = "Password change required",
)
return subject, credential_generation(jwt_secret)
except jwt.InvalidTokenError:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Invalid or expired token",
)
View on GitHub (pinned to 203007d190)
Solutions
- Complete the password change via the change-password endpoint/UI; the flag clears and normal access resumes.
- Custom clients should detect 403 with detail 'Password change required' and route the user to the change-password flow.
- Admins: confirm the flag is intended (it is usually set by an explicit reset action).
Example fix
# before
resp = requests.get(f"{base}/api/things", headers=auth)
# after
resp = requests.get(f"{base}/api/things", headers=auth)
if resp.status_code == 403 and 'Password change required' in resp.text:
requests.post(f"{base}/auth/change-password", json={"old": old, "new": new}, headers=auth) Defensive patterns
Strategy: try-catch
Try / catch
try:
client.get('/api/data')
except HTTPStatusError as e:
if e.response.status_code == 403 and 'Password change required' in e.response.text:
prompt_password_change() # complete the flow, then retry Prevention
- Implement the change-password flow in custom clients, not just the official UI.
- Treat this 403 distinctly from permission denials: it is a workflow gate, not an ACL.
- After admin-forced resets, drive users straight to the change-password screen.
When it happens
Trigger: An admin reset the user's password (setting the must-change flag) and the user keeps calling normal endpoints with the old still-valid JWT; first-login password policies; the user skips the forced change-password screen in a custom client.
Common situations: Password-expiry policies; security incidents forcing credential rotation; custom API clients that never implemented the change-password step and only call regular endpoints.
Related errors
- Local (stdio) MCP servers can only be configured from the Un
- Directory not allowed
- Invalid or expired token
- Invalid or expired API key
- Invalid token payload
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/763e5cdd88ede18f.
Report an issue: GitHub.