{"record":{"id":"01ac3cd4eb710aa9","repo":"odysseus-dev/odysseus","slug":"password-is-required","errorCode":null,"errorMessage":"Password is required","messagePattern":"Password is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"routes/calendar_routes.py","lineNumber":928,"sourceCode":"            })\n        return {\"accounts\": safe}\n\n    @router.post(\"/config/accounts\")\n    async def add_caldav_account(request: Request):\n        \"\"\"Add a new CalDAV account.\"\"\"\n        import uuid as _uuid\n        owner = _require_user(request)\n        try:\n            body = await request.json()\n        except Exception:\n            body = {}\n        from src.caldav_sync import validate_caldav_url\n        try:\n            url = validate_caldav_url(body.get(\"url\", \"\"))\n        except ValueError as e:\n            raise HTTPException(400, str(e))\n        if not body.get(\"password\"):\n            raise HTTPException(400, \"Password is required\")\n        from src.secret_storage import encrypt\n        new_acc = {\n            \"id\": str(_uuid.uuid4()),\n            \"label\": (body.get(\"label\") or \"\").strip() or \"CalDAV\",\n            \"url\": url,\n            \"username\": (body.get(\"username\") or \"\").strip(),\n            \"password\": encrypt(body[\"password\"]),\n        }\n        accounts = _get_caldav_accounts(owner)\n        accounts.append(new_acc)\n        _save_caldav_accounts(owner, accounts)\n        return {\"ok\": True, \"id\": new_acc[\"id\"]}\n\n    @router.put(\"/config/accounts/{account_id}\")\n    async def update_caldav_account(account_id: str, request: Request):\n        \"\"\"Update an existing CalDAV account by id.\"\"\"\n        owner = _require_user(request)\n        try:","sourceCodeStart":910,"sourceCodeEnd":946,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/calendar_routes.py#L910-L946","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\ncurl -X POST /config/accounts -d '{\"url\": \"https://caldav.example.com/\", \"username\": \"u\"}'\n\n# after\ncurl -X POST /config/accounts -H 'Content-Type: application/json' \\\n  -d '{\"url\": \"https://caldav.example.com/\", \"username\": \"u\", \"password\": \"secret\"}'","handlingStrategy":"validation","validationCode":"if (!form.password || !form.password.trim()) {\n  showError('Password is required');\n  return;\n}\nawait api.post('/config/accounts', {url: form.url, username: form.username, password: form.password});","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["caldav","validation","http-400","fastapi","authentication"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}