{"record":{"id":"a80500b675880d2b","repo":"HKUDS/DeepTutor","slug":"invalid-book-id-book-id-r","errorCode":null,"errorMessage":"Invalid book id: {book_id!r}","messagePattern":"Invalid book id: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"deeptutor/book/storage.py","lineNumber":73,"sourceCode":"    text = json.dumps(payload, ensure_ascii=False, indent=2, default=str)\n    _atomic_write_text(path, text)\n\n\n_SAFE_ID = re.compile(r\"[^A-Za-z0-9_-]\")\n\n\ndef _safe_book_id(book_id: str) -> str:\n    \"\"\"Reduce a caller-supplied id to something that cannot escape its root.\n\n    Book ids arrive in request bodies and are used verbatim as directory names.\n    Ids the engine mints are ``bk_<hex>``; anything containing a separator or a\n    dot segment is either a bug or an attempt to walk out of the workspace, and\n    neither should reach the filesystem. Mirrors the containment rule in\n    ``services/storage/attachment_store.py``.\n    \"\"\"\n    cleaned = _SAFE_ID.sub(\"\", (book_id or \"\").strip())\n    if not cleaned:\n        raise ValueError(f\"Invalid book id: {book_id!r}\")\n    return cleaned\n\n\ndef _read_json(path: Path) -> Any | None:\n    if not path.exists():\n        return None\n    try:\n        with open(path, encoding=\"utf-8\") as f:\n            return json.load(f)\n    except (OSError, json.JSONDecodeError) as exc:\n        logger.warning(f\"Failed to read JSON {path}: {exc}\")\n        return None\n\n\n# ─────────────────────────────────────────────────────────────────────────────\n# Public API\n# ─────────────────────────────────────────────────────────────────────────────\n","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/book/storage.py#L55-L91","documentation":"Error \"Invalid book id: {book_id!r}\" thrown in HKUDS/DeepTutor.","triggerScenarios":"Thrown at deeptutor/book/storage.py:73 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}