{"record":{"id":"5a4e7078b54efef4","repo":"anthropics/skills","slug":"parent-comment-parent-id-not-found","errorCode":null,"errorMessage":"parent comment {parent_id} not found","messagePattern":"parent comment (.+?) not found","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/docx/scripts/comment.py","lineNumber":261,"sourceCode":") -> tuple[int, str, str]:\n    unpacked_dir = Path(unpacked_dir)\n    if not raw:\n        text = xml_escape(text)\n    author = xml_escape(author, {'\"': \"&quot;\"})\n    initials = xml_escape(initials, {'\"': \"&quot;\"})\n    word = unpacked_dir / \"word\"\n    if not word.exists():\n        raise FileNotFoundError(f\"{word} not found (not an unpacked .docx?)\")\n\n    comments = word / \"comments.xml\"\n    if comment_id is None:\n        comment_id = _next_comment_id(comments)\n\n    parent_para = None\n    if parent_id is not None:\n        parent_para = _find_para_id(comments, parent_id) if comments.exists() else None\n        if not parent_para:\n            raise ValueError(f\"parent comment {parent_id} not found\")\n\n    para_id, durable_id = _generate_hex_id(), _generate_hex_id()\n    ts = datetime.now(timezone.utc).strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n\n    if not comments.exists():\n        shutil.copy(TEMPLATE_DIR / \"comments.xml\", comments)\n    _ensure_comment_relationships(unpacked_dir)\n    _ensure_comment_content_types(unpacked_dir)\n    _append_xml(\n        comments,\n        \"w:comments\",\n        COMMENT_XML.format(\n            id=comment_id, author=author, date=ts, initials=initials,\n            para_id=para_id, text=text,\n        ),\n    )\n\n    ext = word / \"commentsExtended.xml\"","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/anthropics/skills/blob/f6656c1256d5a8adfa37db9110046ef20bac644c/skills/docx/scripts/comment.py#L243-L279","documentation":"Raised by add_comment() when a parent_id was supplied for a reply comment but no comment with that ID could be found in word/comments.xml (or comments.xml does not exist yet, so no parent can exist). It prevents writing a reply that references a nonexistent parent, which would produce a corrupt or orphaned comment thread.","triggerScenarios":"Calling add_comment(..., parent_id=N) where N is not a comment id present in word/comments.xml — e.g. N came from a previous run against a different document, comments.xml was deleted/never created, or the ID was read from a tool that reports para ids rather than comment ids.","commonSituations":"Reply workflows where the caller cached comment IDs from an older version of the document; documents with no existing comments (comments.xml absent) where a reply was attempted; ID confusion between w:comment/@w:id, w15:paraId, and durableId.","solutions":["List existing comments first (read word/comments.xml w:comment/@w:id) and pass a verified id as parent_id.","If the document genuinely has no comments, drop parent_id and create a top-level comment instead.","Re-extract IDs from the CURRENT document version rather than reusing IDs from a prior edit session.","If comments.xml is missing unexpectedly, confirm you are operating on the same unpacked tree the earlier comments were added to."],"exampleFix":"# before\nadd_comment(unpacked_dir=d, text=\"reply\", parent_id=7)  # ValueError if 7 absent\n\n# after\nfrom defusedxml import minidom\nids = {c.getAttribute(\"w:id\") for c in minidom.parse(str(d/\"word\"/\"comments.xml\")).getElementsByTagName(\"w:\", )} if False else {c.getAttribute(\"w:id\") for c in minidom.parse(str(d/\"word\"/\"comments.xml\")).getElementsByTagName(\"w:comment\")}\nadd_comment(unpacked_dir=d, text=\"reply\", parent_id=7 if \"7\" in ids else None)","handlingStrategy":"validation","validationCode":"from pathlib import Path\nfrom defusedxml import minidom\n\ndef comment_ids(unpacked_dir: Path) -> set[str]:\n    f = Path(unpacked_dir) / \"word\" / \"comments.xml\"\n    if not f.exists():\n        return set()\n    return {c.getAttribute(\"w:id\") for c in minidom.parseString(f.read_bytes()).getElementsByTagName(\"w:comment\")}","typeGuard":null,"tryCatchPattern":"try:\n    add_comment(unpacked_dir=d, text=\"reply\", parent_id=pid)\nexcept ValueError as e:\n    if \"parent comment\" in str(e):\n        add_comment(unpacked_dir=d, text=text)  # degrade to top-level comment, or re-fetch IDs\n    else:\n        raise","preventionTips":["Fetch the live comment ID list from word/comments.xml in the same run before replying.","Never reuse comment IDs across edits of the document.","For brand-new threads, omit parent_id.","Distinguish w:id (comment id) from w15:paraId/durableId — only w:id is accepted as parent_id."],"tags":["docx","comments","validation","ooxml"],"backgroundTag":null,"analyzedSha":"f6656c1256d5a8adfa37db9110046ef20bac644c","analyzedAt":"2026-08-14T16:09:17.493Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}