{"record":{"id":"dabb9a51fe2ac724","repo":"thephpleague/flysystem","slug":"invalid-stream-provided-expected-stream-resource-dabb9a","errorCode":null,"errorMessage":"Invalid stream provided, expected stream resource, received resource of type {type}","messagePattern":"Invalid stream provided, expected stream resource, received resource of type (.+?)","errorType":"exception","errorClass":"InvalidStreamProvided","httpStatus":null,"severity":"error","filePath":"src/Filesystem.php","lineNumber":266,"sourceCode":"\n        if ($this->adapter instanceof PublicUrlGenerator) {\n            return $this->adapter;\n        }\n\n        return null;\n    }\n\n    /**\n     * @param mixed $contents\n     */\n    private function assertIsResource($contents): void\n    {\n        if (is_resource($contents) === false) {\n            throw new InvalidStreamProvided(\n                \"Invalid stream provided, expected stream resource, received \" . gettype($contents)\n            );\n        } elseif (($type = get_resource_type($contents)) !== 'stream') {\n            throw new InvalidStreamProvided(\n                \"Invalid stream provided, expected stream resource, received resource of type \" . $type\n            );\n        }\n    }\n\n    /**\n     * @param resource $resource\n     */\n    private function rewindStream($resource): void\n    {\n        if (ftell($resource) !== 0 && stream_get_meta_data($resource)['seekable']) {\n            rewind($resource);\n        }\n    }\n\n    private function resolveConfigForMoveAndCopy(array $config): Config\n    {\n        $retainVisibility = $this->config->get(Config::OPTION_RETAIN_VISIBILITY, $config[Config::OPTION_RETAIN_VISIBILITY] ?? true);","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/thephpleague/flysystem/blob/b277b5dc3d56650b68904117124e79c851e12376/src/Filesystem.php#L248-L284","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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."],"exampleFix":"// before\nforeach ($urls as $i => $url) {\n    $filesystem->writeStream(\"dl/$i\", $stream); // $stream closed on 2nd iteration\n    fclose($stream);\n}\n\n// after\nforeach ($urls as $i => $url) {\n    $stream = fopen($tempFiles[$i], 'rb');\n    $filesystem->writeStream(\"dl/$i\", $stream);\n    fclose($stream); // fresh resource each iteration\n}","handlingStrategy":"type-guard","validationCode":"if (is_resource($stream) && get_resource_type($stream) !== 'stream') {\n    throw new InvalidArgumentException(\n        'Expected a stream resource, got a ' . get_resource_type($stream) . ' resource'\n    );\n}","typeGuard":"function isOpenStreamResource(mixed $value): bool\n{\n    // closed streams report type 'Unknown' in PHP 8, so this also rejects them\n    return is_resource($value) && get_resource_type($value) === 'stream';\n}","tryCatchPattern":"use League\\Flysystem\\InvalidStreamProvided;\n\ntry {\n    $filesystem->writeStream($path, $resource);\n} catch (InvalidStreamProvided $e) {\n    if (str_contains($e->getMessage(), 'resource of type')) {\n        // wrong handle type (curl/process/closed stream): reopen as a file stream\n        $resource = fopen($sourcePath, 'rb');\n        $filesystem->writeStream($path, $resource);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["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."],"tags":["php","flysystem","stream","write-stream","resource-type","closed-stream"],"backgroundTag":"invalid-stream-resource","analyzedSha":"b277b5dc3d56650b68904117124e79c851e12376","analyzedAt":"2026-08-17T04:28:35.741Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}