{"record":{"id":"4410d60e32927a5a","repo":"anthropics/skills","slug":"no-relationship-in-this-package-names-a-part-we-ca","errorCode":null,"errorMessage":"no relationship in this package names a part we can resolve. Refusing to treat every file as unreferenced.","messagePattern":"no relationship in this package names a part we can resolve\\. Refusing to treat every file as unreferenced\\.","errorType":"exception","errorClass":"RefusedToClean","httpStatus":null,"severity":"error","filePath":"skills/pptx/scripts/clean.py","lineNumber":257,"sourceCode":"    changed = False\n\n    for override in list(dom.getElementsByTagName(\"Override\")):\n        part_name = override.getAttribute(\"PartName\").lstrip(\"/\")\n        if part_name in removed_files:\n            if override.parentNode:\n                override.parentNode.removeChild(override)\n                changed = True\n\n    if changed:\n        with open(ct_path, \"wb\") as f:\n            f.write(dom.toxml(encoding=\"utf-8\"))\n\n\ndef clean_unused_files(unpacked_dir: Path) -> list[str]:\n    all_removed = []\n\n    if list(unpacked_dir.rglob(\"*.rels\")) and not get_referenced_files(unpacked_dir):\n        raise RefusedToClean(\n            \"no relationship in this package names a part we can resolve. \"\n            \"Refusing to treat every file as unreferenced.\"\n        )\n\n    slides_removed = remove_orphaned_slides(unpacked_dir)\n    all_removed.extend(slides_removed)\n\n    trash_removed = remove_trash_directory(unpacked_dir)\n    all_removed.extend(trash_removed)\n\n    while True:\n        removed_rels = remove_orphaned_rels_files(unpacked_dir)\n        referenced = get_referenced_files(unpacked_dir)\n        removed_files = remove_orphaned_files(unpacked_dir, referenced)\n\n        total_removed = removed_rels + removed_files\n        if not total_removed:\n            break","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/anthropics/skills/blob/f6656c1256d5a8adfa37db9110046ef20bac644c/skills/pptx/scripts/clean.py#L239-L275","documentation":"clean_unused_files() guards against catastrophic deletion: if the package contains .rels files but get_referenced_files() resolves none of them to actual parts, every file would look 'unreferenced' and a naive cleaner would delete the whole package. It raises RefusedToClean instead, treating total resolution failure as a parse/corruption problem rather than an unreferenced-file problem.","triggerScenarios":"Cleaning a pptx where all relationship targets fail resolution — e.g. every target contains backslashes or escapes the package (triggering opc_target failures that are swallowed per-entry), targets point at parts that do not exist on disk, or the unpacked tree is missing files that the rels reference.","commonSituations":"Corrupt or non-conformant decks from converters (Windows-style rels targets); partially extracted archives where some parts failed to unpack; hand-modified packages; the same root causes as errors 14-16 surfacing at the clean orchestration layer.","solutions":["Re-save the deck with PowerPoint or LibreOffice ('soffice --headless --convert-to pptx') to rebuild conformant relationships, then retry.","Inspect the .rels files for backslash targets or traversal targets (fix per errors 14/15/16) and repair them.","Re-unpack the original pptx completely and confirm no parts are missing on disk.","Run a package validator to find which relationships fail to resolve."],"exampleFix":"# before\nclean_unused_files(unpacked_dir)  # RefusedToClean: nothing resolvable\n\n# after\nimport subprocess, zipfile, tempfile\nwith tempfile.TemporaryDirectory() as td:\n    subprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"pptx\", \"--outdir\", td, str(src)], check=True)\n    with zipfile.ZipFile(next(Path(td).glob(\"*.pptx\"))) as zf:\n        zf.extractall(unpacked_dir_unpacked)\nclean_unused_files(unpacked_dir_unpacked)","handlingStrategy":"try-catch","validationCode":"import zipfile\n\ndef package_has_resolvable_rels(path: str) -> bool:\n    # cheap smoke check: every internal rel target should at least exist as a part\n    import re, posixpath\n    with zipfile.ZipFile(path) as zf:\n        names = set(zf.namelist())\n        for name in [n for n in names if n.endswith(\".rels\")]:\n            base = posixpath.dirname(posixpath.dirname(name))\n            for m in re.finditer(rb'Target=\"([^\"]+)\"[^>]*?(TargetMode=\"External\")?', zf.read(name)):\n                t = m.group(1).decode()\n                if m.group(2) or \"://\" in t or t.startswith(\"/\"):\n                    continue\n                if posixpath.normpath(posixpath.join(base, t)) not in names:\n                    return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    removed = clean_unused_files(unpacked_dir)\nexcept RefusedToClean as e:\n    log.warning(\"package %s not cleaned (unresolvable relationships): %s\", src, e)\n    # keep original untouched; re-save via LibreOffice and retry once, else skip","preventionTips":["Treat RefusedToClean as a stop signal — never work around it by forcing deletion.","Normalize decks through a conformant re-save before cleaning pipelines.","Validate that .rels targets resolve to existing parts before cleanup jobs.","Operate on copies; preserve originals for destructive operations."],"tags":["pptx","ooxml","safety","cleaning","relationships"],"backgroundTag":null,"analyzedSha":"f6656c1256d5a8adfa37db9110046ef20bac644c","analyzedAt":"2026-08-14T16:09:17.493Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}