HKUDS/DeepTutor · warning · HTTPException

Document not found

Error message

Document not found

What it means

404 raised by _validate_doc_id when the document id fails the strict regex ^[0-9a-f]{8,32}$ (8-32 lowercase hex chars). This is a security guard: the id is used to build a path and DELETE runs rmtree, so traversal like 'a/../../x' must never pass. Malformed ids are intentionally reported as 404, not 400, to avoid leaking the validation rule.

Source

Thrown at deeptutor/api/routers/co_writer.py:527

        raise HTTPException(status_code=404, detail="Tool call not found")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ─────────────────────────────────────────────────────────────────────────────
# Document CRUD (multi-project Co-Writer)
# ─────────────────────────────────────────────────────────────────────────────

# Storage builds paths as `documents/doc_{doc_id}`; an unvalidated id like
# "a/../../x" would escape the documents root (and DELETE runs rmtree).
_DOC_ID_RE = re.compile(r"^[0-9a-f]{8,32}$")


def _validate_doc_id(doc_id: str) -> str:
    if not _DOC_ID_RE.fullmatch(doc_id):
        raise HTTPException(status_code=404, detail="Document not found")
    return doc_id


class CreateDocumentRequest(BaseModel):
    title: str | None = None
    content: str = ""


class UpdateDocumentRequest(BaseModel):
    title: str | None = None
    content: str | None = None


class DocumentResponse(BaseModel):
    id: str
    title: str
    content: str
    created_at: float

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Always use the exact id returned by POST /co-writer/documents
  2. Check the id matches ^[0-9a-f]{8,32}$ before calling
  3. If you control id generation, switch to hex ids (e.g. uuid4().hex)

Example fix

// before
doc_id = str(uuid.uuid4())  # contains dashes -> 404
// after
doc_id = uuid.uuid4().hex   # 32 lowercase hex chars
Defensive patterns

Strategy: validation

Validate before calling

import re
DOC_ID_RE = re.compile(r'^[0-9a-f]{8,32}$')
assert DOC_ID_RE.fullmatch(doc_id), 'bad doc id'

Type guard

def is_valid_doc_id(doc_id: str) -> bool:
    import re
    return bool(re.fullmatch(r'[0-9a-f]{8,32}', doc_id))

Prevention

When it happens

Trigger: Calling GET/PUT/DELETE /co-writer/documents/{doc_id} with an id containing uppercase, non-hex characters, slashes/dots, or one shorter than 8 / longer than 32 chars.

Common situations: Client generating its own ids instead of using the id returned by POST /documents, URL-encoding issues that mangle the id, or path-traversal probes.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/31a4954ebd055837. Report an issue: GitHub.