Hit this in production today and tracked it down. Posting in case anyone else runs into it.
Setup: Cloudflare R2 bucket via the S3-compatible endpoint, accessed through async-aws/s3 (3.2.0) + league/flysystem-async-aws-s3 (3.31.0). PutObject works fine. HeadObject returns 200 with the
right ETag and Content-Type, but getContentLength() returns null, which makes flysystem throw UnableToRetrieveMetadata::fileSize.
It's not async-aws's fault — Cloudflare's edge proxy is the problem.
Reproduced by dumping the raw response headers async-aws receives:
HTTP/1.1 200 OK
Date: Mon, 27 Apr 2026 21:19:33 GMT
Content-Type: image/svg+xml
Last-Modified: Mon, 27 Apr 2026 21:10:20 GMT
ETag: W/"32338883f6b6423933d02f75f6dd2cdc"
Content-Encoding: gzip
Server: cloudflare
CF-RAY: 9f30ddbbea10d3b4-FRA
Content-Encoding: gzip is set, no Content-Length. Cloudflare's proxy gzips compressible HEAD responses, and per HTTP semantics Content-Length then refers to the compressed body — but HEAD has no
body, so the header gets dropped entirely. Tools that send Accept-Encoding: identity (curl, mc) don't trigger this; tools that accept gzip (most HTTP clients including symfony/http-client by
default) do.
Workaround that fixes it for me — pass a custom HTTP client that asks for identity encoding:
app.async_aws.http_client:
class: Symfony\Contracts\HttpClient\HttpClientInterface
factory: ['Symfony\Component\HttpClient\HttpClient', 'create']
arguments:
- headers:
Accept-Encoding: identity
AsyncAws\S3\S3Client:
arguments:
- endpoint: '%env(AWS_ENDPOINT)%'
...
- null
- '@app.async_aws.http_client'
After this, getContentLength() returns the correct size.
Opening this mainly so it's findable for the next person who hits it. Happy to send a PR if you'd want Accept-Encoding: identity set by default on HEAD requests, but that may have side effects on
AWS proper, so I'll leave the call to the maintainers.
Hit this in production today and tracked it down. Posting in case anyone else runs into it.
Setup: Cloudflare R2 bucket via the S3-compatible endpoint, accessed through
async-aws/s3(3.2.0) +league/flysystem-async-aws-s3(3.31.0).PutObjectworks fine.HeadObjectreturns 200 with theright ETag and Content-Type, but
getContentLength()returnsnull, which makesflysystemthrowUnableToRetrieveMetadata::fileSize.It's not async-aws's fault — Cloudflare's edge proxy is the problem.
Reproduced by dumping the raw response headers async-aws receives:
Content-Encoding: gzipis set, noContent-Length. Cloudflare's proxy gzips compressible HEAD responses, and per HTTP semanticsContent-Lengththen refers to the compressed body — but HEAD has nobody, so the header gets dropped entirely. Tools that send
Accept-Encoding: identity(curl, mc) don't trigger this; tools that accept gzip (most HTTP clients includingsymfony/http-clientbydefault) do.
Workaround that fixes it for me — pass a custom HTTP client that asks for identity encoding:
After this,
getContentLength()returns the correct size.Opening this mainly so it's findable for the next person who hits it. Happy to send a PR if you'd want
Accept-Encoding: identityset by default onHEADrequests, but that may have side effects onAWS proper, so I'll leave the call to the maintainers.