thephpleague/flysystem · error · InvalidStreamProvided

Invalid stream provided, expected stream resource, received

Error message

Invalid stream provided, expected stream resource, received resource of type {type}

What it means

Filesystem::writeStream()'s assertIsResource() accepts only resources whose get_resource_type() is 'stream'. A valid PHP resource of another type — CurlHandle, process resource, a closed stream (type becomes 'Unknown' after fclose in PHP 8), SoapClient — triggers InvalidStreamProvided with the actual resource type in the message.

Source

Thrown at src/Filesystem.php:266

        if ($this->adapter instanceof PublicUrlGenerator) {
            return $this->adapter;
        }

        return null;
    }

    /**
     * @param mixed $contents
     */
    private function assertIsResource($contents): void
    {
        if (is_resource($contents) === false) {
            throw new InvalidStreamProvided(
                "Invalid stream provided, expected stream resource, received " . gettype($contents)
            );
        } elseif (($type = get_resource_type($contents)) !== 'stream') {
            throw new InvalidStreamProvided(
                "Invalid stream provided, expected stream resource, received resource of type " . $type
            );
        }
    }

    /**
     * @param resource $resource
     */
    private function rewindStream($resource): void
    {
        if (ftell($resource) !== 0 && stream_get_meta_data($resource)['seekable']) {
            rewind($resource);
        }
    }

    private function resolveConfigForMoveAndCopy(array $config): Config
    {
        $retainVisibility = $this->config->get(Config::OPTION_RETAIN_VISIBILITY, $config[Config::OPTION_RETAIN_VISIBILITY] ?? true);

View on GitHub (pinned to b277b5dc3d)

Solutions

  1. Open a real file stream with fopen($path, 'rb') and pass that.
  2. Do not reuse a resource after fclose(); restructure loops so each write gets its own fopen/fclose pair.
  3. For curl downloads, write to a php://temp stream or use CURLOPT_FILE with an fopen'd handle, then pass that stream.
  4. Guard with get_resource_type($stream) === 'stream' before calling writeStream() to fail with your own clearer error.

Example fix

// before
foreach ($urls as $i => $url) {
    $filesystem->writeStream("dl/$i", $stream); // $stream closed on 2nd iteration
    fclose($stream);
}

// after
foreach ($urls as $i => $url) {
    $stream = fopen($tempFiles[$i], 'rb');
    $filesystem->writeStream("dl/$i", $stream);
    fclose($stream); // fresh resource each iteration
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (is_resource($stream) && get_resource_type($stream) !== 'stream') {
    throw new InvalidArgumentException(
        'Expected a stream resource, got a ' . get_resource_type($stream) . ' resource'
    );
}

Type guard

function isOpenStreamResource(mixed $value): bool
{
    // closed streams report type 'Unknown' in PHP 8, so this also rejects them
    return is_resource($value) && get_resource_type($value) === 'stream';
}

Try / catch

use League\Flysystem\InvalidStreamProvided;

try {
    $filesystem->writeStream($path, $resource);
} catch (InvalidStreamProvided $e) {
    if (str_contains($e->getMessage(), 'resource of type')) {
        // wrong handle type (curl/process/closed stream): reopen as a file stream
        $resource = fopen($sourcePath, 'rb');
        $filesystem->writeStream($path, $resource);
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Passing the return value of curl_init() or proc_open(); reusing a stream variable after fclose() was already called (closed streams report as 'Unknown'); passing a database connection resource or any non-stream handle to writeStream().

Common situations: Download handlers mixing curl handles and file streams; loops that close streams inside the body but reuse them on the next iteration; long-lived workers holding stale stream references.

Related errors


AI-assisted analysis of thephpleague/flysystem@b277b5dc3d (2026-08-17). Data as JSON: /api/errors/dabb9a51fe2ac724. Report an issue: GitHub.