anthropics/skills · error · ValueError
No frames to save. Add frames with add_frame() first.
Error message
No frames to save. Add frames with add_frame() first.
What it means
GifBuilder.save() refuses to write a GIF when its internal frames list is empty, because there is nothing to encode. The ValueError tells you to call add_frame() first; it is a straightforward precondition violation, not a resource or encoding failure.
Source
Thrown at skills/slack-gif-creator/core/gif_builder.py:180
output_path: str | Path,
num_colors: int = 128,
optimize_for_emoji: bool = False,
remove_duplicates: bool = False,
) -> dict:
"""
Save frames as optimized GIF for Slack.
Args:
output_path: Where to save the GIF
num_colors: Number of colors to use (fewer = smaller file)
optimize_for_emoji: If True, optimize for emoji size (128x128, fewer colors)
remove_duplicates: If True, remove duplicate consecutive frames (opt-in)
Returns:
Dictionary with file info (path, size, dimensions, frame_count)
"""
if not self.frames:
raise ValueError("No frames to save. Add frames with add_frame() first.")
output_path = Path(output_path)
# Remove duplicate frames to reduce file size
if remove_duplicates:
removed = self.deduplicate_frames(threshold=0.9995)
if removed > 0:
print(
f" Removed {removed} nearly identical frames (preserved subtle animations)"
)
# Optimize for emoji if requested
if optimize_for_emoji:
if self.width > 128 or self.height > 128:
print(
f" Resizing from {self.width}x{self.height} to 128x128 for emoji"
)
self.width = 128View on GitHub (pinned to f6656c1256)
Solutions
- Verify frames were added before saving: ensure add_frame() ran at least once
- Validate upstream input (e.g. non-empty prompt/text) before starting the build
- If frames can legitimately be zero, skip the build entirely instead of calling save()
Example fix
# before
gif.save(out_path)
# after
if not gif.frames:
raise ValueError("nothing to render: provide text/scenes first")
gif.save(out_path) Defensive patterns
Strategy: validation
Validate before calling
def builder_has_frames(builder) -> bool:
return len(getattr(builder, "frames", [])) > 0 Try / catch
try:
info = builder.save(out)
except ValueError as e:
if "No frames" in str(e):
return None # skip GIF creation for empty input
raise Prevention
- Check len(builder.frames) right after the frame-generation loop, before save()
- Reject empty user input (text/scenes) at the API boundary
- Log the frame count when building so zero-frame runs are visible
When it happens
Trigger: Calling save(output_path) on a fresh GifBuilder; calling save() after a deduplicate/reset step removed all frames; a frame-generation loop whose condition never fired (e.g. zero scenes parsed from user input) so add_frame() was never reached.
Common situations: Building a GIF from user-supplied text/emoji where empty input yields zero frames; forgetting that add_frame() must precede save() in the builder pipeline; conditional frame loops (only add on success) where all attempts failed silently.
Related errors
- {word} not found (not an unpacked .docx?)
- parent comment {parent_id} not found
- relationship target is not a POSIX part name: {target!r}
- relationship target resolves to nothing: {target!r}
- Command is required for stdio transport
AI-assisted analysis of anthropics/skills@f6656c1256 (2026-08-14).
Data as JSON: /api/errors/34551893abc0454e.
Report an issue: GitHub.