odysseus-dev/odysseus · warning · HTTPException
No documents found
Error message
No documents found
What it means
404 from POST /api/documents/export-zip: ids were supplied, but after querying and filtering the documents the loop wrote zero entries into the zip (wrote == 0). Typically the ids do not match any Document rows (deleted, wrong user's docs) — a partial match writes some files and does not raise.
Source
Thrown at routes/document/document_routes.py:608
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
for doc in docs:
try:
_verify_doc_owner(db, doc, user)
except HTTPException:
continue # skip docs the user doesn't own
ext = _ext.get(doc.language or "text", ".txt")
base = (doc.title or "document").strip() or "document"
base = re.sub(r"[^\w\-. ]+", "", base)[:60].strip() or doc.id
name = base if "." in base else base + ext
i = 1
while name in used:
name = f"{base}-{i}" + ("" if "." in base else ext)
i += 1
used.add(name)
zf.writestr(name, doc.current_content or "")
wrote += 1
if not wrote:
raise HTTPException(404, "No documents found")
return Response(
content=buf.getvalue(),
media_type="application/zip",
headers={"Content-Disposition": 'attachment; filename="documents.zip"'},
)
finally:
db.close()
# ---- PUT /api/document/{doc_id} — user manual edit ----
# Coalesce window: if the last user version was saved within this many
# seconds, update it in-place (user is still actively editing).
# Once the gap exceeds this, the next save creates a new version.
VERSION_COALESCE_SECONDS = 60
@router.put("/api/document/{doc_id}")
async def update_document(request: Request, doc_id: str, req: DocumentUpdate) -> Dict[str, Any]:
user = get_current_user(request)
db = SessionLocal()View on GitHub (pinned to f9235ebbf1)
Solutions
- Re-fetch GET /api/documents/library and export ids that currently exist for this user.
- Trim/normalize ids before sending; drop falsy entries.
- Treat 404 here as 'selection is stale' and prompt a refresh rather than retrying the same ids.
Example fix
// before
await api.post('/api/documents/export-zip', { ids: selectionFromLastHour }); // 404
// after
const live = (await api.get('/api/documents/library')).documents.map(d => d.id);
const ids = selection.filter(id => live.includes(id));
if (ids.length) await api.post('/api/documents/export-zip', { ids }); Defensive patterns
Strategy: validation
Validate before calling
const live = new Set((await api.get('/api/documents/library')).documents.map(d => d.id));
const ids = requestedIds.map(s => s.trim()).filter(id => live.has(id));
if (!ids.length) { refreshLibrary(); return; } Try / catch
try { return await api.post('/api/documents/export-zip', { ids }); }
catch (e) { if (e.status === 404 && /No documents found/.test(e.message)) { await refreshLibrary(); return null; } throw e; } Prevention
- Export only ids confirmed present in a fresh library fetch
- Trim and drop falsy ids before sending
- Prompt a list refresh instead of retrying the same stale ids
When it happens
Trigger: All requested ids are stale/deleted; ids belong to another owner and are filtered out; ids with whitespace or case differences that fail the equality match; empty strings in the ids array.
Common situations: Exporting a selection made before another session deleted those docs; shared id lists between users; copy-paste artifacts in ids.
Related errors
- No documents specified
- Version not found
- Chained task not found
- d && d.detail ? d.detail : ('HTTP ' + res.status)
- result.detail || 'Failed to rename session'
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/d9ddd0de53382607.
Report an issue: GitHub.