kovidgoyal/kitty · error · ConvertFailed

Failed to render {len(unseen)} out of {len(m)} frames of ani

Error message

Failed to render {len(unseen)} out of {len(m)} frames of animation

What it means

Raised (as ConvertFailed) by render_image when multi-frame animation rendering was requested (get_multiple_frames=True) but some frames listed by ImageMagick were never produced: after processing, the 'unseen' set of expected frame filenames is non-empty. This means IM failed mid-animation or skipped frames.

Source

Thrown at kittens/tui/images.py:283

                sz, pos = parts[3].split('+', 1)
                f.canvas_width, f.canvas_height = map(positive_int, sz.split('x', 1))
                f.canvas_x, f.canvas_y = map(int, pos.split('+', 1))
            except Exception:
                raise OutdatedImageMagick(f'Unexpected output filename: {x!r} produced by ImageMagick command: {last_imagemagick_cmd}')
            f.path = output_prefix + f'-{index}.{m.mode}'
            os.rename(os.path.join(tdir, x), f.path)
            check_resize(f)
    f = ans.frames[0]
    if f.width != ans.width or f.height != ans.height:
        with open(f.path, 'r+b') as ff:
            data = ff.read()
            ff.seek(0)
            ff.truncate()
            cd = create_canvas(data, f.width, f.canvas_x, f.canvas_y, ans.width, ans.height, 3 if ans.mode == 'rgb' else 4)
            ff.write(cd)
    if get_multiple_frames:
        if unseen:
            raise ConvertFailed(path, f'Failed to render {len(unseen)} out of {len(m)} frames of animation')
    elif not ans.frames[0].path:
        raise ConvertFailed(path, 'Failed to render image')

    return ans


def render_as_single_image(
    path: str,
    m: ImageData,
    available_width: int,
    available_height: int,
    scale_up: bool,
    tdir: str | None = None,
    remove_alpha: str = '',
    flip: bool = False,
    flop: bool = False,
) -> tuple[str, int, int]:
    import tempfile

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Test the same file with 'magick identify file.gif' and a manual convert to see if IM drops frames
  2. Upgrade ImageMagick to a recent version
  3. Catch ConvertFailed for animations and fall back to rendering a single frame (get_multiple_frames=False)

Example fix

# before
img = render_image(path, width=80, get_multiple_frames=True)  # ConvertFailed
# after
try:
    img = render_image(path, width=80, get_multiple_frames=True)
except ConvertFailed:
    img = render_image(path, width=80)  # single frame fallback
Defensive patterns

Strategy: fallback

Validate before calling

import subprocess
def count_frames(path: str) -> int:
    out = subprocess.run(['magick', 'identify', path], capture_output=True, text=True).stdout
    return max(1, len(out.strip().splitlines()))

Try / catch

from kittens.tui.images import ConvertFailed
try:
    img = render_image(path, width=80, get_multiple_frames=True)
except ConvertFailed:
    img = render_image(path, width=80)  # single-frame fallback

Prevention

When it happens

Trigger: Calling render_image(..., get_multiple_frames=True) on an animated GIF/WebP where ImageMagick reports N frames in its output listing but generates fewer files (e.g. frames where 'unseen' filenames remain after the rename loop).

Common situations: Animated GIFs with disposal/optimization that trip IM bugs; partial disk-full conditions in the temp dir; ImageMagick versions that silently drop duplicate frames; corrupted animations where IM aborts partway.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/e99e499f5a808e8d. Report an issue: GitHub.