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
- Convert legacy .ppt via LibreOffice to .pptx
- Re-export/re-save the deck in PowerPoint
- 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
- Convert .ppt decks before upload
- Verify integrity of pptx zips after transfer
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
- ConceptDesignAgent prompts are not configured.
- VisualReviewAgent prompts are not configured.
- math_animator requires optional dependencies. Install with `
- Model not configured for agent {self.agent_name}. Please act
- The model provider interrupted this response. Please retry.
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/9fb0f275fb2c749d.
Report an issue: GitHub.