HKUDS/DeepTutor · error · ManimRenderError

Image mode requires code blocks wrapped in ### YON_IMAGE_n_S

Error message

Image mode requires code blocks wrapped in ### YON_IMAGE_n_START ### / END ###.

What it means

Raised by _extract_pptx when python-pptx fails to open the presentation and the raw-OOXML fallback recovers no text. Mirrors the XLSX/DOCX pattern: primary parser error + empty fallback → CorruptDocumentError with the underlying message.

Source

Thrown at deeptutor/agents/math_animator/renderer.py:87

        )

    async def _render_video(self, *, code_path: Path, quality: str) -> RenderedArtifact:
        scene_name = self._extract_scene_name(code_path.read_text(encoding="utf-8"))
        await self._emit_progress(f"Launching Manim scene `{scene_name}`.")
        await self._run_manim(
            code_path=code_path, scene_name=scene_name, quality=quality, save_last_frame=False
        )
        video_file = self._find_rendered_file(".mp4")
        target_name = slugify_filename(f"{self.turn_id}-{scene_name}.mp4", f"{self.turn_id}.mp4")
        artifact_path = self.artifacts_dir / target_name
        artifact_path.write_bytes(video_file.read_bytes())
        await self._emit_progress(f"Saved rendered video as {artifact_path.name}.")
        return self._build_artifact(artifact_path, "video", "video/mp4", "Animation video")

    async def _render_image_blocks(self, *, code: str, quality: str) -> list[RenderedArtifact]:
        matches = list(YON_IMAGE_PATTERN.finditer(code))
        if not matches:
            raise ManimRenderError(
                "Image mode requires code blocks wrapped in ### YON_IMAGE_n_START ### / END ###."
            )

        residual = YON_IMAGE_PATTERN.sub("", code).strip()
        if residual:
            raise ManimRenderError("Image mode code must only contain YON_IMAGE anchor blocks.")

        artifacts: list[RenderedArtifact] = []
        for idx, match in enumerate(matches, start=1):
            block_code = match.group(2).strip()
            block_path = self.source_dir / f"image_block_{idx:02d}.py"
            block_path.write_text(block_code, encoding="utf-8")
            scene_name = self._extract_scene_name(block_code)
            await self._emit_progress(
                f"Rendering image block {idx}/{len(matches)} with scene `{scene_name}`."
            )
            await self._run_manim(
                code_path=block_path,

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Convert legacy .ppt via LibreOffice to .pptx
  2. Re-export/re-save the deck in PowerPoint
  3. Repair the zip container (unzip + rezip) if truncated

Example fix

// before
text = extract_text_from_bytes(data, filename="deck.pptx")  # actually .ppt

// after
subprocess.run(["soffice","--headless","--convert-to","pptx","deck.ppt"], check=True)
text = extract_text_from_bytes(Path("deck.pptx").read_bytes(), filename="deck.pptx")
Defensive patterns

Strategy: validation

Validate before calling

def is_ooxml(data: bytes) -> bool:
    return data[:2] == b"PK"

if not is_ooxml(data):
    convert_ppt_to_pptx(fn)

Try / catch

except CorruptDocumentError as e:
    if "failed to open PPTX" in str(e):
        soffice_convert(fn, "pptx") and retry

Prevention

When it happens

Trigger: A .ppt file renamed to .pptx; a corrupted or truncated pptx zip; a presentation where python-pptx fails on malformed slide XML and no fallback <a:t> text exists.

Common situations: Old PowerPoint decks renamed rather than converted; decks from third-party exporters with non-standard XML; partial uploads.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/9fb0f275fb2c749d. Report an issue: GitHub.