thephpleague/flysystem · error · UnableToProvideChecksum

Unable to get checksum for $path: $reason

Error message

Unable to get checksum for $path: $reason

What it means

AsyncAwsS3Adapter::checksum() obtains the ETag by calling fetchFileMetadata() (a HeadObject request). When that metadata retrieval fails for any reason, the UnableToRetrieveMetadata exception is rethrown as UnableToProvideChecksum with the message 'Unable to get checksum for $path: $reason'. The original exception is chained as $previous, so the reason string comes from the underlying failure.

Source

Thrown at src/AsyncAwsS3/AsyncAwsS3Adapter.php:565

        try {
            return $this->client->getUrl($this->bucket, $this->prefixer->prefixPath($path));
        } catch (Throwable $exception) {
            throw UnableToGeneratePublicUrl::dueToError($path, $exception);
        }
    }

    public function checksum(string $path, Config $config): string
    {
        $algo = $config->get('checksum_algo', 'etag');

        if ($algo !== 'etag') {
            throw new ChecksumAlgoIsNotSupported();
        }

        try {
            $metadata = $this->fetchFileMetadata($path, 'checksum')->extraMetadata();
        } catch (UnableToRetrieveMetadata $exception) {
            throw new UnableToProvideChecksum($exception->reason(), $path, $exception);
        }

        if ( ! isset($metadata['ETag'])) {
            throw new UnableToProvideChecksum('ETag header not available.', $path);
        }

        return trim($metadata['ETag'], '"');
    }

    public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string
    {
        try {
            $request = new GetObjectRequest([
                'Bucket' => $this->bucket,
                'Key' => $this->prefixer->prefixPath($path),
            ] + $config->get('get_object_options', []));

            return $this->client->presign($request, DateTimeImmutable::createFromInterface($expiresAt));

View on GitHub (pinned to b277b5dc3d)

Solutions

  1. Verify the path exists first with $filesystem->fileExists($path) and handle the race window gracefully.
  2. Inspect $exception->getPrevious() to find the real cause (404, 403, DNS, credentials) and fix that.
  3. For permission errors, grant s3:GetObject (and s3:ListBucket on the bucket) to the credentials used by the AsyncAws S3Client.
  4. Catch UnableToProvideChecksum at the call site and retry or degrade, since transient network errors surface here too.

Example fix

// before
$checksum = $filesystem->checksum('reports/2024/q1.csv'); // file was deleted -> throws

// after
if ( ! $filesystem->fileExists('reports/2024/q1.csv')) {
    throw new RuntimeException('Report missing, cannot verify integrity.');
}

try {
    $checksum = $filesystem->checksum('reports/2024/q1.csv', ['checksum_algo' => 'etag']);
} catch (UnableToProvideChecksum $e) {
    $reason = $e->getPrevious() ? $e->getPrevious()->getMessage() : $e->getMessage();
    // handle 403 (permissions), 404 (raced delete), network errors
}
Defensive patterns

Strategy: try-catch

Validate before calling

if ( ! $filesystem->fileExists($path)) {
    throw new InvalidArgumentException("Cannot checksum missing path: {$path}");
}
// fileExists uses HeadObject, so permission problems surface there with clearer context

Try / catch

use League\Flysystem\UnableToProvideChecksum;

try {
    $etag = $filesystem->checksum($path);
} catch (UnableToProvideChecksum $e) {
    $previous = $e->getPrevious();
    // branch on the wrapped UnableToRetrieveMetadata reason (404 vs 403 vs network)
    log_warning('checksum failed', ['path' => $path, 'reason' => $e->getMessage()]);
    throw $e;
}

Prevention

When it happens

Trigger: $adapter->checksum() or $filesystem->checksum() on a path that does not exist (404), the IAM principal lacks s3:GetObject / s3:ListBucket permission so HeadObject is denied, the S3-compatible endpoint is unreachable, credentials are expired, or the path resolves to a directory.

Common situations: Checksumming a file that was concurrently deleted; wrong key case or missing path prefix; read-only IAM roles that allow ListObjects but not HeadObject; S3-compatible services (MinIO, R2, third-party gateways) with auth or clock-skew problems.

Related errors


AI-assisted analysis of thephpleague/flysystem@b277b5dc3d (2026-08-17). Data as JSON: /api/errors/c74f56ac341be6e6. Report an issue: GitHub.