odysseus-dev/odysseus · warning · HTTPException
Version not found
Error message
Version not found
What it means
Raised by GET /api/document/{doc_id}/version/{num} when the document exists and is owned by the caller, but no DocumentVersion row matches (document_id, version_number). It is a 404 meaning the requested version number is out of range — either higher than version_count or lower than the earliest stored version.
Source
Thrown at routes/document/document_routes.py:805
db.close()
# ---- GET /api/document/{doc_id}/version/{num} ----
@router.get("/api/document/{doc_id}/version/{num}")
async def get_version(request: Request, doc_id: str, num: int) -> Dict[str, Any]:
user = get_current_user(request)
db = SessionLocal()
try:
# Verify ownership
doc = db.query(Document).filter(Document.id == doc_id).first()
if not doc:
raise HTTPException(404, "Document not found")
_verify_doc_owner(db, doc, user)
ver = db.query(DocumentVersion).filter(
DocumentVersion.document_id == doc_id,
DocumentVersion.version_number == num,
).first()
if not ver:
raise HTTPException(404, "Version not found")
return _version_to_dict(ver)
finally:
db.close()
# ---- POST /api/document/{doc_id}/restore/{num} ----
@router.post("/api/document/{doc_id}/restore/{num}")
async def restore_version(request: Request, doc_id: str, num: int) -> Dict[str, Any]:
user = get_current_user(request)
db = SessionLocal()
try:
doc = db.query(Document).filter(Document.id == doc_id).first()
if not doc:
raise HTTPException(404, "Document not found")
_verify_doc_owner(db, doc, user)
old_ver = db.query(DocumentVersion).filter(
DocumentVersion.document_id == doc_id,
DocumentVersion.version_number == num,View on GitHub (pinned to f9235ebbf1)
Solutions
- List valid version numbers first via GET /api/document/{doc_id}/versions and constrain user selection to that set.
- Remember version numbers are 1-based here (version_number starts at 1, restore uses version_count + 1).
- If racing concurrent edits, re-fetch the version list after any save/restore before requesting a specific version.
Example fix
# before
ver = requests.get(f"{base}/api/document/{doc}/version/{num}").json()
# after
versions = requests.get(f"{base}/api/document/{doc}/versions").json()
valid = {v["version_number"] for v in versions}
ver = (requests.get(f"{base}/api/document/{doc}/version/{num}").json()
if num in valid else None) Defensive patterns
Strategy: validation
Validate before calling
import requests
def valid_version_numbers(base: str, doc_id: str, cookies: dict) -> set:
vs = requests.get(f"{base}/api/document/{doc_id}/versions", cookies=cookies).json()
return {v["version_number"] for v in vs} Try / catch
try:
ver = requests.get(f"{base}/api/document/{doc}/version/{num}").json()
except requests.HTTPError as e:
if e.response.status_code == 404:
ver = pick_latest_version(doc) # fall back to newest
else:
raise Prevention
- Constrain version pickers to numbers from the versions list.
- Re-fetch the list after concurrent saves — numbers shift.
- Assume 1-based numbering, not 0-based.
When it happens
Trigger: Requesting /version/5 when the doc only has versions 1-3; racing a concurrent save that renumbers versions; requesting version 0 or a negative number via a hand-edited URL; the version row was deleted by a purge that kept only recent versions.
Common situations: A version-history dropdown showing stale numbers after another tab created fewer versions than expected; off-by-one errors in client code that assumes version numbers start at 0.
Related errors
- Invalid remote_host — must be host or user@host, no SSH opti
- Invalid ssh_port
- Unknown wipe kind: {kind!r}
- Username required
- {key} must be an integer
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/baf201ae3c3212ce.
Report an issue: GitHub.