roboflow/supervision · error · RuntimeError

Video writer is not open

Error message

Video writer is not open

What it means

Raised by the PyAV VideoWriter.write() when the writer never opened successfully (or was released). Construction stores any init exception in self._error and defers it; the first write() then raises RuntimeError chained to that root cause — typically an unsupported codec, an unwritable path, or a PyAV/ffmpeg problem.

Source

Thrown at src/supervision/_cv2/_video.py:232

            self._container = av.open(str(filename), mode="w")
            rate = Fraction(str(fps)).limit_denominator(100_000)
            self._stream = self._container.add_stream(codec, rate=rate)
            self._stream.width = self._width
            self._stream.height = self._height
            self._stream.pix_fmt = pixel_format
            self._opened = True
        except Exception as exc:
            self._error = exc
            self.release()

    def isOpened(self) -> bool:
        """Return whether the writer initialized successfully."""
        return self._opened

    def write(self, frame: npt.NDArray[np.uint8]) -> None:
        """Encode one BGR frame and mux all packets produced by the encoder."""
        if not self._opened or self._container is None or self._stream is None:
            raise RuntimeError("Video writer is not open") from self._error
        if frame.shape != (self._height, self._width, 3):
            raise ValueError(
                "Video frame must have shape "
                f"({self._height}, {self._width}, 3), got {frame.shape}"
            )
        if frame.dtype != np.uint8:
            raise ValueError("Video frames must use uint8 dtype")

        video_frame = av.VideoFrame.from_ndarray(
            np.ascontiguousarray(frame), format="bgr24"
        )
        for packet in self._stream.encode(video_frame):
            self._container.mux(packet)

    def release(self) -> None:
        """Flush delayed encoder packets and close the output container."""
        container = self._container
        stream = self._stream

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Check writer.isOpened() immediately after construction and fail fast with your own error if False.
  2. Inspect the chained exception (__cause__) to find the real init failure — usually fix the codec fourcc or the output path.
  3. Verify the output directory exists and is writable before creating the writer.
  4. Do not call write() after release().

Example fix

# before
writer = cv2.VideoWriter('out.mp4', fourcc, fps, (w, h))
writer.write(frame)  # RuntimeError: Video writer is not open

# after
writer = cv2.VideoWriter('out.mp4', fourcc, fps, (w, h))
if not writer.isOpened():
    raise RuntimeError(f'cannot open out.mp4 with {fourcc}')
writer.write(frame)
Defensive patterns

Strategy: validation

Validate before calling

writer = cv2.VideoWriter(path, fourcc, fps, (w, h))
if not writer.isOpened():
    raise RuntimeError(f'failed to open video writer for {path}')

Try / catch

try:
    writer.write(frame)
except RuntimeError as e:
    if 'not open' in str(e) and e.__cause__ is not None:
        raise RuntimeError(f'writer init failed: {e.__cause__}') from e
    raise

Prevention

When it happens

Trigger: Calling writer.write(frame) after creating a VideoWriter whose av.open or stream creation failed (bad codec, permission denied, missing directory), or writing after release().

Common situations: Real OpenCV silently absorbs open failures and isOpened() returns False, so code that skips the isOpened() check keeps 'working' (producing empty files); the fallback surfaces the failure at first write instead, surprising ported code.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/870cf95dcafd5cbf. Report an issue: GitHub.