odysseus-dev/odysseus · warning · HTTPException
Password is required
Error message
Password is required
What it means
Raised as HTTP 400 by POST /config/accounts when body.get('password') is falsy. The route requires a non-empty password for every new CalDAV account because CalDAV servers authenticate per-request; there is no anonymous-account path, so an account row without credentials would be unusable.
Source
Thrown at routes/calendar_routes.py:928
})
return {"accounts": safe}
@router.post("/config/accounts")
async def add_caldav_account(request: Request):
"""Add a new CalDAV account."""
import uuid as _uuid
owner = _require_user(request)
try:
body = await request.json()
except Exception:
body = {}
from src.caldav_sync import validate_caldav_url
try:
url = validate_caldav_url(body.get("url", ""))
except ValueError as e:
raise HTTPException(400, str(e))
if not body.get("password"):
raise HTTPException(400, "Password is required")
from src.secret_storage import encrypt
new_acc = {
"id": str(_uuid.uuid4()),
"label": (body.get("label") or "").strip() or "CalDAV",
"url": url,
"username": (body.get("username") or "").strip(),
"password": encrypt(body["password"]),
}
accounts = _get_caldav_accounts(owner)
accounts.append(new_acc)
_save_caldav_accounts(owner, accounts)
return {"ok": True, "id": new_acc["id"]}
@router.put("/config/accounts/{account_id}")
async def update_caldav_account(account_id: str, request: Request):
"""Update an existing CalDAV account by id."""
owner = _require_user(request)
try:View on GitHub (pinned to f9235ebbf1)
Solutions
- Include a non-empty 'password' string in the JSON body: {'url': ..., 'username': ..., 'password': '...'} with Content-Type: application/json.
- Make the password field required in the UI and disable the submit button until it is non-empty.
- If the password is definitely filled in, verify the request body is valid JSON — the route's silent body={} fallback makes any JSON parse failure look like a missing password or URL.
Example fix
# before
curl -X POST /config/accounts -d '{"url": "https://caldav.example.com/", "username": "u"}'
# after
curl -X POST /config/accounts -H 'Content-Type: application/json' \
-d '{"url": "https://caldav.example.com/", "username": "u", "password": "secret"}' Defensive patterns
Strategy: validation
Validate before calling
if (!form.password || !form.password.trim()) {
showError('Password is required');
return;
}
await api.post('/config/accounts', {url: form.url, username: form.username, password: form.password}); Prevention
- Mark the password input required and disable submit until it is non-empty.
- Never send an empty string for optional fields you intend to skip — omit the key instead.
- Remember the route treats a malformed JSON body as {}: a missing-password 400 may actually mean the body was not valid JSON.
When it happens
Trigger: POST /config/accounts with {'url': 'https://...', 'username': 'u'} (no password key); password set to '' or null; JSON body missing entirely so the except branch sets body={} and the password check fails after URL validation passes.
Common situations: Frontend 'Add account' form not marking the password field required; password field bound to an empty state variable on first render; client sending multipart/form-data which request.json() cannot parse, collapsing body to {}; user pasting only whitespace.
Related errors
- {key} must be an integer
- str(e)
- Document is not linked to a source PDF
- msg_id and content are required
- Message is required
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/01ac3cd4eb710aa9.
Report an issue: GitHub.