DEV Community

Nidhin NP
Nidhin NP

Posted on

S3 fileExists (HeadObject) fails only in Alpine Docker (PHP-FPM) with "Error parsing XML", but GetObject works

Hi everyone,

I'm facing a really specific issue with S3 file existence checks (Storage::fileExists()) only when running my Laravel application inside a php:8.2-fpm-alpine Docker container.

The Problem:

Calling Storage::disk('cloud')->fileExists('path/to/file.pdf') consistently throws League\Flysystem\UnableToCheckFileExistence.

The underlying exception caught using a direct AWS SDK headObject call logs: Error parsing response for HeadObject: AWS parsing error: Error parsing XML: String could not be parsed as XML.

Crucially, the exact same code works perfectly fine outside Docker (using Laravel Valet on macOS). Both Valet and Docker are confirmed to be using the identical AWS credentials from the .env file.

What Also Works (Inside Docker):

Other S3 operations work perfectly inside the Docker container:

Storage::put()

Storage::readStream()

Storage::download()

Storage::get()

A simple PHP script run inside the container using curl_exec to make a HEAD request to the same S3 file URL succeeds with an HTTP 200 OK.

Debugging Done (Ruled Out):

IAM Permissions: Confirmed policy allows s3:GetObject (which authorizes HeadObject). Keys are identical between Valet (working) and Docker (failing).

Basic Network/DNS: ping and curl from the container's shell to the S3 endpoint work fine.

SSL Certificates: Added ca-certificates to the Docker image and confirmed via php-fpm -i that openssl.cafile and openssl.capath are correctly set. The PHP curl_exec script also succeeded with SSL verification enabled.

Clock Skew: Container time is correct.

Interfering Processes: Disabled Laravel Nightwatch.

Guzzle Config: Tried forcing HTTP/1.1, changing stream options, and disabling SSL verify (verify => false) in config/filesystems.php - none fixed the parsing error.

Environment:

Laravel (latest stable version)

Docker Image: php:8.2-fpm-alpine

Filesystem Disk Driver: s3 (using league/flysystem-aws-s3-v3 and aws/aws-sdk-php)

AWS Region: me-central-1

AWS_USE_PATH_STYLE_ENDPOINT is false.

The Core Question: Why would the HeadObject request, specifically when initiated by the AWS SDK/Guzzle stack within PHP-FPM on Alpine, fail with a parsing error, even though GetObject requests work, a direct HEAD request using PHP's curl_exec works, and the entire setup works fine outside Docker on Valet? Is there a known bug or subtle configuration issue related to this specific combination (AWS SDK/Guzzle + PHP-FPM + Alpine) that only affects HEAD requests?

Has anyone encountered this specific failure mode with HeadObject on Alpine? Right now, my only workaround is to avoid fileExists and use readStream() in a try...catch, but I'd prefer to fix the root cause.

Thanks for any insights!

Top comments (0)