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
- Open a real file stream with fopen($path, 'rb') and pass that.
- Do not reuse a resource after fclose(); restructure loops so each write gets its own fopen/fclose pair.
- For curl downloads, write to a php://temp stream or use CURLOPT_FILE with an fopen'd handle, then pass that stream.
- 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
- Never reuse a stream variable after fclose() — set it to null or reopen per iteration.
- For curl downloads use CURLOPT_FILE with an fopen'd stream instead of passing the curl handle around.
- Assert get_resource_type() === 'stream' in shared upload helpers.
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
- Invalid stream provided, expected stream resource, received
- Unable to get checksum for $path: $reason
- Unable to get checksum for $path: $reason
- ETag header not available.
- Unable to get checksum for $path: $reason
AI-assisted analysis of thephpleague/flysystem@b277b5dc3d (2026-08-17).
Data as JSON: /api/errors/dabb9a51fe2ac724.
Report an issue: GitHub.