While using Laravel’s HTTP client to download files, I encountered this cryptic error:
cURL error 0: The cURL request was retried 3 times and did not succeed. The most likely reason for the failure is that cURL was unable to rewind the body of the request…
Turned out it was caused by specifying a negative timeout (as I wanted to disable timeouts):
Http::timeout(-1)->get($url);
Calling timeout(-1)
seems like a good way to allow infinite request time. But under the hood, Laravel uses Guzzle, which uses cURL — and negative timeout values are invalid for cURL. This causes unexpected behavior in stream handling and retries, often leading to errors like:
- Failed retries due to non-rewindable request bodies.
- Broken downloads or incomplete responses.
- cURL crashes or errors with large files or signed URLs (like AWS S3 presigned links).
Don’t use -1
for unlimited timeout. Use a large positive value instead:
$response = Http::timeout(600) // 10 minutes
->throw()
->get($url);
Or stream directly to disk:
Http::sink(storage_path('app/file.pdf'))
->timeout(600)
->get($url);
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.