odysseus-dev/odysseus · error · HTTPException
Referenced upload is no longer available: {missing_id}
Error message
Referenced upload is no longer available: {missing_id} What it means
HTTP 409 raised when _reserve_calendar_references finds an upload id referenced by the request payload that cannot be reserved for the caller: reserve_upload_references extracts internal upload ids (URLs, PDF source refs, attachment lines) from the payload values and owner-checks them against the upload handler. A missing id means the referenced upload was deleted, expired, or belongs to another user, so the calendar write is rejected before persisting dangling references.
Source
Thrown at routes/calendar_routes.py:815
for d in results:
d["truncated"] = True
return results
# ── Routes ──
def setup_calendar_routes(upload_handler=None) -> APIRouter:
router = APIRouter(prefix="/api/calendar", tags=["calendar"])
def _reserve_calendar_uploads(request: Request, *values) -> None:
missing_id = reserve_upload_references(
upload_handler,
effective_user(request),
*values,
)
if missing_id:
raise HTTPException(409, f"Referenced upload is no longer available: {missing_id}")
# ── CalDAV multi-account helpers ─────────────────────────────────────────
def _get_caldav_accounts(owner: str) -> list:
from src.caldav_sync import _load_caldav_accounts
return _load_caldav_accounts(owner)
def _save_caldav_accounts(owner: str, accounts: list) -> None:
from routes.prefs_routes import _load_for_user, _save_for_user
prefs = _load_for_user(owner) or {}
prefs["caldav_accounts"] = accounts
prefs.pop("caldav", None)
_save_for_user(owner, prefs)
# ── CalDAV config routes (backward-compat single-account API) ────────────
@router.get("/config")
async def get_config(request: Request):View on GitHub (pinned to f9235ebbf1)
Solutions
- Remove or re-upload the attachment named in the 409 message, then retry.
- If the upload should exist, verify it belongs to the same owner and was not cleaned up.
- When copying events across users/instances, strip internal upload references or re-attach the files under the target owner.
Defensive patterns
Strategy: validation
Validate before calling
const UPLOAD_RE = /[internal upload url pattern]/; // extract ids like the server does
function referencedUploads(text) { return [...text.matchAll(UPLOAD_RE)].map(m => m[1]); }
// verify each id still exists and is owned by the caller before POSTing the event Try / catch
catch (e) {
if (e.status === 409) { const id = e.message.split(': ').pop(); stripReference(id); retry(); }
else throw e;
} Prevention
- Only attach uploads created by the same account in the same instance.
- When copying event content across users, strip internal upload URLs first.
- Handle 409 by removing the named reference rather than re-uploading blindly.
When it happens
Trigger: Creating/updating a calendar event whose description or attachment field references /uploads/... or an attachment line for a file that no longer exists or is owned by another account. The 409 body names the first offending id.
Common situations: Copy-pasting event content with an old upload URL between users or instances; upload expired/cleaned by retention policy; multi-user deployment where uploads are owner-scoped.
Related errors
- Referenced upload is no longer available: {missing_id}
- Username already taken
- Document PDF marker references an upload you do not own
- Referenced upload is no longer available: {missing_id}
- Server error ' + res.status
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/5b5ae7e3ab42ef72.
Report an issue: GitHub.