{"record":{"id":"90463cbba3177053","repo":"anthropics/skills","slug":"libreoffice-rendered-len-visible-images-page-s","errorCode":null,"errorMessage":"LibreOffice rendered {len(visible_images)} page(s) for {visible_count} visible slide(s) of {len(slide_info)}; thumbnails would be mislabeled","messagePattern":"LibreOffice rendered (.+?) page\\(s\\) for (.+?) visible slide\\(s\\) of (.+?); thumbnails would be mislabeled","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/pptx/scripts/thumbnail.py","lineNumber":151,"sourceCode":"            part = rid_to_part.get(sld_id.getAttribute(\"r:id\"))\n            if part is not None and part in present:\n                slides.append(\n                    {\"name\": posixpath.basename(part), \"hidden\": _is_hidden(zf, part)}\n                )\n\n        return slides\n\n\ndef build_slide_list(\n    slide_info: list[dict],\n    visible_images: list[Path],\n    temp_dir: Path,\n) -> list[tuple[Path, str]]:\n    visible_count = sum(1 for info in slide_info if not info[\"hidden\"])\n    rendered_hidden = len(visible_images) == len(slide_info) != visible_count\n\n    if not rendered_hidden and visible_count != len(visible_images):\n        raise ValueError(\n            f\"LibreOffice rendered {len(visible_images)} page(s) for {visible_count} \"\n            f\"visible slide(s) of {len(slide_info)}; thumbnails would be mislabeled\"\n        )\n\n    if visible_images:\n        with Image.open(visible_images[0]) as img:\n            placeholder_size = img.size\n    else:\n        placeholder_size = (1920, 1080)\n\n    slides = []\n    visible_idx = 0\n\n    for info in slide_info:\n        if info[\"hidden\"] and not rendered_hidden:\n            placeholder_path = temp_dir / f\"hidden-{info['name']}.jpg\"\n            placeholder_img = create_hidden_placeholder(placeholder_size)\n            placeholder_img.save(placeholder_path, \"JPEG\")","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/anthropics/skills/blob/f6656c1256d5a8adfa37db9110046ef20bac644c/skills/pptx/scripts/thumbnail.py#L133-L169","documentation":"build_slide_list() in thumbnail.py aligns LibreOffice-rendered page images with the deck's slide list. It knows how many visible (non-hidden) slides there are; if the number of rendered images differs AND the special case 'LibreOffice rendered hidden slides too' (len(images)==len(slide_info)!=visible_count) does not hold, the one-to-one mapping between images and slides is broken and thumbnails would be mislabeled — so it refuses with ValueError.","triggerScenarios":"Rendering a deck where soffice produced fewer/more pages than visible slides: e.g. get_slide_info miscounted hidden slides (show attribute parsed as hidden when not), LibreOffice skipped a corrupt slide, export produced a partial PDF/PNG set, or a race where output images were read before conversion finished.","commonSituations":"Headless LibreOffice versions that render hidden slides differently than desktop; decks with unusual 'show' attribute values; truncated PDF-to-image conversion; temp-dir cleanup or glob ordering issues picking up stale images from a previous run.","solutions":["Check the LibreOffice version/behavior: re-render with 'soffice --headless --convert-to pdf' and count pages vs visible slides to see which side is wrong.","Ensure the temp image directory is fresh per run so stale images are not counted.","Re-save the deck in PowerPoint to normalize hidden-slide (show) attributes, then retry.","If a corrupt slide is skipped by LibreOffice, repair or remove that slide and re-render."],"exampleFix":"# before\nslides = build_slide_list(slide_info, visible_images, temp_dir)  # may raise\n\n# after\nvisible_count = sum(1 for i in slide_info if not i[\"hidden\"])\nif visible_count != len(visible_images):\n    raise RuntimeError(f\"render mismatch: {len(visible_images)} images vs {visible_count} visible slides — re-render deck\")\nslides = build_slide_list(slide_info, visible_images, temp_dir)","handlingStrategy":"validation","validationCode":"def render_count_matches(slide_info: list[dict], visible_images: list[Path]) -> bool:\n    visible_count = sum(1 for i in slide_info if not i[\"hidden\"])\n    rendered_hidden = len(visible_images) == len(slide_info) != visible_count\n    return rendered_hidden or visible_count == len(visible_images)","typeGuard":null,"tryCatchPattern":"try:\n    slides = build_slide_list(slide_info, visible_images, temp_dir)\nexcept ValueError as e:\n    if \"thumbnails would be mislabeled\" in str(e):\n        log.warning(\"render mismatch (%s) — re-rendering deck once\", e)\n        visible_images = render_pages(pptx_path, temp_dir)  # fresh render, clean temp dir first\n        slides = build_slide_list(slide_info, visible_images, temp_dir)\n    else:\n        raise","preventionTips":["Use a fresh temp directory per render so stale images cannot skew counts.","Verify the LibreOffice export completed (conversion subprocess exit 0) before globbing images.","Pin a known LibreOffice version in CI so hidden-slide rendering behavior is stable.","Compare page count of the exported PDF against visible slide count before aligning thumbnails."],"tags":["pptx","libreoffice","thumbnails","rendering","validation"],"backgroundTag":null,"analyzedSha":"f6656c1256d5a8adfa37db9110046ef20bac644c","analyzedAt":"2026-08-14T16:09:17.493Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}