Intervention/image · error · StreamException

Failed to rewind position of stream

Error message

Failed to rewind position of stream

What it means

Before draining the stream the decoder rewinds it to position 0; rewind() returned false. This happens on non-seekable streams (pipes, sockets, custom wrappers without seek support) or streams whose underlying handle is gone. It is a StreamException (FilesystemException family), thrown before any decoding starts.

Source

Thrown at src/Drivers/Imagick/Decoders/StreamImageDecoder.php:46

     * {@inheritdoc}
     *
     * @see DecoderInterface::decode()
     *
     * @throws InvalidArgumentException
     * @throws StreamException
     * @throws DriverException
     * @throws StateException
     */
    public function decode(mixed $input): ImageInterface
    {
        if (!is_resource($input) || !in_array(get_resource_type($input), ['file', 'stream'])) {
            throw new InvalidArgumentException('Image source must be a resource of type "file" or "stream"');
        }

        $contents = '';
        $rewind = rewind($input);
        if ($rewind === false) {
            throw new StreamException('Failed to rewind position of stream');
        }

        while (!feof($input)) {
            $chunk = fread($input, 1024);
            if ($chunk === false) {
                throw new StreamException('Failed to read image from stream');
            }

            $contents .= $chunk;
        }

        try {
            return parent::decode($contents);
        } catch (DecoderException) {
            throw new ImageDecoderException(
                'Failed to decode image from stream, could be unsupported image format',
            );
        }

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Buffer non-seekable streams first and pass the bytes: $manager->read(stream_get_contents($input))
  2. Or copy into a seekable buffer: $tmp = fopen('php://temp', 'r+b'); stream_copy_to_stream($input, $tmp); then pass $tmp
  3. Check stream_get_meta_data($input)['seekable'] before handing the stream over

Example fix

// before
$image = $manager->read(STDIN); // pipe is not rewindable -> StreamException

// after
$image = $manager->read(stream_get_contents(STDIN)); // pass bytes as binary string
Defensive patterns

Strategy: validation

Validate before calling

$meta = stream_get_meta_data($stream);
if (!$meta['seekable']) {
    $stream = fopen('php://temp', 'r+b');
    stream_copy_to_stream($original, $stream);
}
$image = $manager->read($stream);

Type guard

function isSeekableFileStream(mixed $value): bool
{
    return is_resource($value)
        && in_array(get_resource_type($value), ['file', 'stream'], true)
        && stream_get_meta_data($value)['seekable'] === true;
}

Prevention

When it happens

Trigger: Passing a pipe from popen()/proc_open(), the STDIN constant, a socket stream from fsockopen(), or a custom stream wrapper that does not implement seekable reads.

Common situations: CLI tools reading images from stdin; fetching from network sockets; stream wrappers over HTTP that only support sequential reads.

Related errors


AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23). Data as JSON: /api/errors/31c6996f3c324929. Report an issue: GitHub.