{"record":{"id":"68f10eddaec58809","repo":"nexu-io/open-design","slug":"slide-part-is-missing-resolved","errorCode":null,"errorMessage":"slide part is missing: {resolved}","messagePattern":"slide part is missing: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"plugins/community/humanize-ppt/scripts/pptx_qa.py","lineNumber":89,"sourceCode":"    if target.startswith(\"/\"):\n        return target.lstrip(\"/\")\n    return posixpath.normpath(posixpath.join(posixpath.dirname(source_part), target))\n\n\ndef _ordered_slide_parts(zf: zipfile.ZipFile) -> list[str]:\n    presentation = \"ppt/presentation.xml\"\n    root = _read_xml(zf, presentation)\n    rels = _relationships(zf, presentation)\n    parts: list[str] = []\n    for slide_id in root.findall(\".//p:sldIdLst/p:sldId\", NS):\n        rel_id = slide_id.attrib.get(f\"{{{REL}}}id\")\n        rel = rels.get(rel_id or \"\", {})\n        target = rel.get(\"Target\")\n        if not target:\n            raise ValueError(f\"slide relationship is missing for {rel_id or 'unknown id'}\")\n        resolved = _resolve_target(presentation, target)\n        if resolved not in zf.namelist():\n            raise ValueError(f\"slide part is missing: {resolved}\")\n        parts.append(resolved)\n    return parts\n\n\ndef _text(root: ET.Element) -> str:\n    return \" \".join(\n        (node.text or \"\").strip()\n        for node in root.findall(\".//a:t\", NS)\n        if (node.text or \"\").strip()\n    )\n\n\ndef _tokens(value: str) -> set[str]:\n    return {\n        token.lower()\n        for token in re.findall(r\"[A-Za-z0-9]+|[\\u3400-\\u9fff]\", value)\n        if token.strip()\n    }","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/plugins/community/humanize-ppt/scripts/pptx_qa.py#L71-L107","documentation":"Raised in _ordered_slide_parts (pptx_qa.py) immediately after the relationship check: once a slide relationship Target is resolved into a part path, the code confirms that path exists in the .pptx zip via `zf.namelist()`. If the slide XML part referenced by the relationship is absent from the archive, it raises ValueError. This catches packages whose relationships point at parts that were never packaged.","triggerScenarios":"Running pptx_qa on a .pptx where presentation.xml.rels has a Target like 'slides/slide5.xml' but the archive contains no such entry; or where Target resolved through _resolve_target lands on a path not in namelist(). Common with stripped/slimmed packages or partially extracted decks.","commonSituations":"A tool that rewrote relationships without re-zipping the corresponding slide XML; file extraction/repackaging that dropped slide parts; a deck that was edited to remove slides but whose presentation.xml still lists them; cross-package Target resolution bugs in converters producing absolute or wrongly-relative paths.","solutions":["List the archive contents to see which slide parts exist: `unzip -l deck.pptx | grep slides/slide` and compare against the rels targets.","Round-trip the file through PowerPoint/Keynote to reconcile presentation.xml with the packaged parts, then retry.","Regenerate the deck from the upstream producer (python-pptx script, exporter) rather than patching the broken zip by hand.","If only a few slides are missing, accept that the deck is damaged and run pptx_qa on a known-good backup copy."],"exampleFix":"// before\npython3 pptx_qa.py inspect deck.pptx\n# -> ValueError: slide part is missing: ppt/slides/slide5.xml\n\n// after\nunzip -l deck.pptx | grep slide   # confirm which parts exist\n# regenerate/re-save deck, then:\npython3 pptx_qa.py inspect deck.pptx","handlingStrategy":"try-catch","validationCode":"import zipfile\n\ndef all_slide_parts_present(path: str) -> bool:\n    with zipfile.ZipFile(path) as zf:\n        names = set(zf.namelist())\n        try:\n            from pptx_qa import _ordered_slide_parts  # reuse the resolver\n            for part in _ordered_slide_parts(zf):\n                if part not in names:\n                    return False\n        except ValueError:\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    parts = _ordered_slide_parts(zf)\nexcept ValueError as exc:\n    raise SystemExit(f\"Deck is missing slide parts: {exc}. Re-export from the source tool.\") from exc","preventionTips":["Confirm slide parts exist in the archive before parsing: `unzip -l deck.pptx | grep slides/slide`.","Re-export decks from the original tool rather than patching the zip.","When accepting user uploads, validate package integrity up front and reject corrupt files with a clear message.","Cross-check rels Targets against namelist() to catch dangling references early."],"tags":["powerpoint","ooxml","zip","file-corruption","pptx-qa","validation"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}