{"record":{"id":"432156faa5c2c2a9","repo":"matplotlib/matplotlib","slug":"can-not-start-iterating-the-frames-for-the-initial","errorCode":null,"errorMessage":"Can not start iterating the frames for the initial draw. This can be caused by passing in a 0 length sequence for *frames*.\n\nIf you passed *frames* as a generator it may be exhausted due to a previous display or save.","messagePattern":"Can not start iterating the frames for the initial draw\\. This can be caused by passing in a 0 length sequence for \\*frames\\*\\.\n\nIf you passed \\*frames\\* as a generator it may be exhausted due to a previous display or save\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"lib/matplotlib/animation.py","lineNumber":1777,"sourceCode":"                        pass\n                return gen()\n            else:\n                return itertools.islice(self.new_frame_seq(), self._save_count)\n\n    def _init_draw(self):\n        super()._init_draw()\n        # Initialize the drawing either using the given init_func or by\n        # calling the draw function with the first item of the frame sequence.\n        # For blitting, the init_func should return a sequence of modified\n        # artists.\n        if self._init_func is None:\n            try:\n                frame_data = next(self.new_frame_seq())\n            except StopIteration:\n                # we can't start the iteration, it may have already been\n                # exhausted by a previous save or just be 0 length.\n                # warn and bail.\n                warnings.warn(\n                    \"Can not start iterating the frames for the initial draw. \"\n                    \"This can be caused by passing in a 0 length sequence \"\n                    \"for *frames*.\\n\\n\"\n                    \"If you passed *frames* as a generator \"\n                    \"it may be exhausted due to a previous display or save.\"\n                )\n                return\n            self._draw_frame(frame_data)\n        else:\n            self._drawn_artists = self._init_func()\n            if self._blit:\n                if self._drawn_artists is None:\n                    raise RuntimeError('When blit=True, the init_func must '\n                                       'return a sequence of Artist objects.')\n                for a in self._drawn_artists:\n                    a.set_animated(self._blit)\n        self._save_seq.clear()\n","sourceCodeStart":1759,"sourceCodeEnd":1795,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/animation.py#L1759-L1795","documentation":"FuncAnimation._init_draw, when no init_func was given, draws the initial frame by calling next() on a freshly created frame sequence. If frames was an empty sequence, or a generator that a previous save()/display already consumed, StopIteration is caught and this UserWarning is emitted - the animation is left without initial artists. Generators are single-pass, so reusing one animation for a second save/display is the usual culprit.","triggerScenarios":"frames=gen followed by anim.save('a.mp4') then anim.save('b.mp4') (the generator is exhausted by the first save); frames=[] or another empty sequence; passing an already-consumed iterator object.","commonSituations":"Saving the same animation twice (e.g. mp4 and gif); interactive display followed by a save; building frames lazily to save memory and forgetting iterators are one-shot.","solutions":["Pass a re-iterable frames: a list (frames=list(gen)), tuple, range, or plain integer count.","Pass a callable returning a fresh iterator each time: frames=lambda: gen_factory() (frames may be any callable taking no args).","Alternatively, create a new FuncAnimation for each output, or supply init_func so the initial draw consumes no frame."],"exampleFix":"# before\nframes = (f(i) for i in data)          # generator, single pass\nanim = FuncAnimation(fig, update, frames=frames)\nanim.save('a.mp4')\nanim.save('b.mp4')                     # exhausted -> warning\n\n# after\nanim = FuncAnimation(fig, update, frames=list(data))  # re-iterable\nanim.save('a.mp4')\nanim.save('b.mp4')","handlingStrategy":"validation","validationCode":"def reusable_frames(frames):\n    if callable(frames):\n        return frames                    # re-invoked per iteration\n    if iter(frames) is iter(frames):     # single-pass iterator/generator\n        return list(frames)              # materialize once\n    return frames                        # list/tuple/range are re-iterable","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass bare generators as frames; use lists, tuples, ranges, ints, or zero-arg callables.","Plan one animation per output, or make frames re-iterable before the first save.","Provide init_func when you want the initial draw not to depend on the frame sequence."],"tags":["matplotlib","animation","funcanimation","exhausted-generator","userwarning"],"backgroundTag":"exhausted-generator","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}