Intervention/image · error · StreamException

Failed to rewind position of stream

Error message

Failed to rewind position of stream

What it means

Before reading, the decoder rewinds the stream to its start; rewind() returning false means the stream is not seekable or has no position to return to. This StreamException reports a capability of the stream, not anything about the image data.

Source

Thrown at src/Drivers/Gd/Decoders/StreamImageDecoder.php:50

     *
     * @throws InvalidArgumentException
     * @throws StreamException
     * @throws DriverException
     * @throws StateException
     * @throws ImageDecoderException
     * @throws NotSupportedException
     */
    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 = '';
        $result = rewind($input);

        if ($result === 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 the source into a seekable php://temp stream and pass that
  2. Or read the full contents to a string and call $manager->read($contents)
  3. For remote files, fetch with an HTTP client first, or pass the URL so the library handles buffering
  4. Check stream_get_meta_data($fp)['seekable'] before calling decodeStream()

Example fix

// before
$image = $manager->decodeStream(fopen('https://example.com/img.png', 'rb')); // not seekable

// after
$buffer = fopen('php://temp', 'rb+');
stream_copy_to_stream(fopen('https://example.com/img.png', 'rb'), $buffer);
rewind($buffer);
$image = $manager->decodeStream($buffer);
// or: $image = $manager->read(file_get_contents('https://example.com/img.png'));
Defensive patterns

Strategy: validation

Validate before calling

$meta = stream_get_meta_data($fp);
if (!$meta['seekable']) {
    $buffer = fopen('php://temp', 'rb+');
    stream_copy_to_stream($fp, $buffer);
    rewind($buffer);
    $fp = $buffer;
}
$manager->decodeStream($fp);

Try / catch

try {
    $image = $manager->decodeStream($fp);
} catch (StreamException $e) {
    $image = $manager->read(stream_get_contents($fp, offset: 0) ?: '');
}

Prevention

When it happens

Trigger: Passing fopen('http://example.com/img.png') (HTTP wrapper, non-seekable), a pipe from popen/proc_open, or a stream whose seeking is unsupported because the underlying transport cannot reposition.

Common situations: Reading remote images directly from the HTTP stream wrapper, piping image bytes from a subprocess, consuming php://input in setups where it cannot be rewound.

Related errors


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