{"record":{"id":"baf8aeb32486f626","repo":"mvanhorn/last30days-skill","slug":"invalid-library-id-in-id-path","errorCode":null,"errorMessage":"invalid library ID in {id_path}","messagePattern":"invalid library ID in (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/library.py","lineNumber":90,"sourceCode":"    return slug or \"last30days\"\n\n\ndef get_or_create_library_id(memory_dir: Path | str) -> str:\n    \"\"\"Return the persisted random namespace for one research library.\"\"\"\n    memory_path = Path(memory_dir).expanduser()\n    memory_path.mkdir(parents=True, exist_ok=True)\n    id_path = memory_path / LIBRARY_ID_FILENAME\n    try:\n        library_id = id_path.read_text(encoding=\"utf-8\").strip()\n    except FileNotFoundError:\n        library_id = uuid.uuid4().hex\n        try:\n            with id_path.open(\"x\", encoding=\"utf-8\") as handle:\n                handle.write(f\"{library_id}\\n\")\n        except FileExistsError:\n            library_id = id_path.read_text(encoding=\"utf-8\").strip()\n    if not _LIBRARY_ID.fullmatch(library_id):\n        raise ValueError(f\"invalid library ID in {id_path}\")\n    return library_id\n\n\ndef is_generated_brief_name(name: str) -> bool:\n    \"\"\"Return whether a filename has the exact library-renderer output shape.\"\"\"\n    return _GENERATED_BRIEF_NAME.fullmatch(name) is not None\n\n\ndef scan_library(\n    memory_dir: Path | str = DEFAULT_MEMORY_DIR,\n    briefs_dir: Path | str = DEFAULT_BRIEFS_DIR,\n) -> tuple[list[LibraryEntry], list[str]]:\n    \"\"\"Return valid saved entries and notes for files that could not be read.\n\n    Hand-edited and foreign files are tolerated: a generic Markdown heading is\n    enough to include a file, while unreadable or unrecognizable files are\n    skipped with a note instead of aborting the entire feed generation.\n    \"\"\"","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/library.py#L72-L108","documentation":"Raised by get_or_create_library_id in library.py when the persisted library ID file (memory_dir/<LIBRARY_ID_FILENAME>) exists but its content does not match _LIBRARY_ID = r'[0-9a-f]{32}' — a 32-char lowercase hex string (a uuid4().hex). The ID namespaces one research library; a corrupt or hand-edited value breaks brief-name generation downstream, so it fails fast with ValueError naming the offending path.","triggerScenarios":"The ID file was hand-edited (uppercase UUID with dashes pasted in, e.g. '550E8400-E29B-...'), truncated by an interrupted write, filled with a placeholder like 'my-library', or corrupted by disk/sync tools; a non-UTF-8 file would surface earlier at read_text.","commonSituations":"Users open the file out of curiosity and 'fix' the ID; cloud-sync or backup tools mangle dot-files; scripts seed the memory dir with example content including a fake ID; partial writes from a crashed first run.","solutions":["Regenerate the ID: delete the ID file and re-run — get_or_create_library_id will create a fresh uuid4().hex via the exclusive-create path.","Or restore the file content to a valid 32-lowercase-hex value if the original ID must be preserved (brief names embed it).","Check what wrote the bad value (editor, sync tool, seeding script) so it does not recur."],"exampleFix":"# before: id file contains\n550E8400-E29B-41D4-A716-446655440000\n\n# after: regenerate\nrm ~/.config/last30days/memory/<library-id-file>\npython -c \"from last30days.scripts.lib.library import get_or_create_library_id; get_or_create_library_id('<memory_dir>')\"","handlingStrategy":"validation","validationCode":"import re\nfrom pathlib import Path\n\nLIBRARY_ID = re.compile(r\"[0-9a-f]{32}\")\n\ndef library_id_ok(memory_dir: Path) -> bool:\n    id_file = memory_dir / LIBRARY_ID_FILENAME\n    return LIBRARY_ID.fullmatch(id_file.read_text(encoding=\"utf-8\").strip()) is not None","typeGuard":"import re\n\n_LIBRARY_ID = re.compile(r\"[0-9a-f]{32}\")\n\ndef is_valid_library_id(value: object) -> bool:\n    return isinstance(value, str) and _LIBRARY_ID.fullmatch(value) is not None","tryCatchPattern":"try:\n    lib_id = get_or_create_library_id(memory_dir)\nexcept ValueError as e:\n    if 'invalid library ID' in str(e):\n        (memory_dir / LIBRARY_ID_FILENAME).unlink(missing_ok=True)\n        lib_id = get_or_create_library_id(memory_dir)  # regenerates a fresh uuid4().hex","preventionTips":["Never hand-edit the library ID file; it must be 32 lowercase hex chars (uuid4().hex).","Exclude the memory dir from sync/backup tools that rewrite dot-files in place.","If seeding example memory dirs, generate the ID with uuid.uuid4().hex, not a placeholder string."],"tags":["filesystem","library","uuid","corruption"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}