{"record":{"id":"3f07fe0be782691c","repo":"odysseus-dev/odysseus","slug":"account-not-found","errorCode":null,"errorMessage":"Account not found","messagePattern":"Account not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"routes/calendar_routes.py","lineNumber":953,"sourceCode":"            \"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:\n            body = await request.json()\n        except Exception:\n            body = {}\n        accounts = _get_caldav_accounts(owner)\n        idx = next((i for i, a in enumerate(accounts) if a.get(\"id\") == account_id), None)\n        if idx is None:\n            raise HTTPException(404, \"Account not found\")\n        acc = dict(accounts[idx])\n        if body.get(\"url\"):\n            from src.caldav_sync import validate_caldav_url\n            try:\n                acc[\"url\"] = validate_caldav_url(body[\"url\"])\n            except ValueError as e:\n                raise HTTPException(400, str(e))\n        if body.get(\"label\") is not None:\n            acc[\"label\"] = (body.get(\"label\") or \"\").strip() or \"CalDAV\"\n        if body.get(\"username\") is not None:\n            acc[\"username\"] = (body.get(\"username\") or \"\").strip()\n        if body.get(\"password\"):\n            from src.secret_storage import encrypt\n            acc[\"password\"] = encrypt(body[\"password\"])\n        accounts[idx] = acc\n        _save_caldav_accounts(owner, accounts)\n        return {\"ok\": True}\n","sourceCodeStart":935,"sourceCodeEnd":971,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/calendar_routes.py#L935-L971","documentation":"Raised as HTTP 404 by PUT /config/accounts/{account_id} when no account in the caller's saved CalDAV account list has an id equal to the path parameter. Accounts are stored per-owner and looked up by exact string match on the 'id' field (a UUID assigned at creation), so the error means either the id is wrong, was deleted, or belongs to a different user.","triggerScenarios":"PUT /config/accounts/{id} with an id copied from a different owner's account; using an id after that account was deleted via DELETE /config/accounts/{id}; a truncated or typo'd UUID in the path; stale client state holding ids from before the account store was reset.","commonSituations":"UI list of accounts not refreshed after a delete, so the next edit targets a dead id; two browser tabs or devices with divergent account lists; the accounts file for this owner was recreated (ids regenerated) while the client cached old ids; case/format mismatch in the UUID string.","solutions":["Re-fetch the account list (GET /config/accounts) and use the current id from that response for the PUT.","If the account is genuinely gone, recreate it with POST /config/accounts instead of updating.","Confirm the account belongs to the authenticated user — ids from another owner always 404 here."],"exampleFix":"// before\nawait fetch(`/config/accounts/${staleAccountId}`, {method: 'PUT', ...});\n\n// after\nconst accounts = await (await fetch('/config/accounts')).json();\nconst acc = accounts.accounts.find(a => a.id === staleAccountId);\nif (acc) {\n  await fetch(`/config/accounts/${acc.id}`, {method: 'PUT', ...});\n} else {\n  // account was deleted elsewhere — recreate or refresh UI\n}","handlingStrategy":"validation","validationCode":"const accounts = await (await fetch('/config/accounts')).json();\nconst exists = accounts.accounts.some(a => a.id === targetId);\nif (!exists) { refreshAccountList(); return; }\nawait fetch(`/config/accounts/${targetId}`, {method: 'PUT', ...});","typeGuard":null,"tryCatchPattern":"try { await api.put(`/config/accounts/${id}`, patch); }\ncatch (e) {\n  if (e.status === 404) { await reloadAccounts(); /* re-sync ids */ }\n  else throw e;\n}","preventionTips":["Always take the account id from a fresh GET /config/accounts response.","Refresh the account list after any create/delete before allowing edits.","Treat 404 on edit as a signal to re-sync client state, not as a hard failure."],"tags":["caldav","http-404","fastapi","rest"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}