thephpleague/flysystem · error · UnableToProvideChecksum
Unable to get checksum for $path: $reason
Error message
Unable to get checksum for $path: $reason
What it means
AwsS3V3Adapter::checksum() performs a HeadObject via fetchFileMetadata(); if that raises UnableToRetrieveMetadata (file missing, access denied, transport error), it is wrapped as UnableToProvideChecksum with message 'Unable to get checksum for $path: $reason' and the original exception chained. This is the generic failure path for every non-ETag-specific checksum problem on the AWS SDK v3 adapter.
Source
Thrown at src/AwsS3V3/AwsS3V3Adapter.php:499
try {
return $this->client->getObjectUrl($this->bucket, $location);
} 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 {
$options = $config->get('get_object_options', []);
$command = $this->client->getCommand('GetObject', [
'Bucket' => $this->bucket,
'Key' => $this->prefixer->prefixPath($path),
] + $options);
View on GitHub (pinned to b277b5dc3d)
Solutions
- Check existence with fileExists() before checksumming and treat a negative result as a missing-file error.
- Read $e->getPrevious()->getMessage() to identify the HeadObject error code (404, 403, 400 wrong region) and fix the underlying client config or policy.
- For 403s, add s3:GetObject on the object ARN plus s3:ListBucket on the bucket so S3 returns 404 instead of 403 for missing keys.
- Wrap in try/catch (UnableToProvideChecksum) with a retry policy for transient network faults.
Example fix
// before
$etag = $filesystem->checksum('uploads/' . $id . '.zip'); // wrong id -> 404 -> throws
// after
try {
$etag = $filesystem->checksum('uploads/' . $id . '.zip');
} catch (UnableToProvideChecksum $e) {
$previous = $e->getPrevious();
if ($previous instanceof UnableToRetrieveMetadata && str_contains($previous->message(), '404')) {
return new NotFoundResponse($id);
}
throw $e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if ( ! $filesystem->fileExists($path)) {
// treat as missing artifact before attempting a HEAD-based checksum
return $fallback ?: throw new DomainException("Artifact not found: {$path}");
} Try / catch
use League\Flysystem\UnableToProvideChecksum;
try {
$etag = $filesystem->checksum($path);
} catch (UnableToProvideChecksum $e) {
$previous = $e->getPrevious(); // UnableToRetrieveMetadata
$reason = $previous?->getMessage() ?? $e->getMessage();
if (str_contains($reason, '404') || str_contains($reason, 'NotFound')) {
return $onMissing($path);
}
if (str_contains($reason, '403') || str_contains($reason, 'AccessDenied')) {
return $onForbidden($path);
}
throw $e; // transport/unknown: retryable at a higher level
} Prevention
- Configure IAM so 404 and 403 are distinguishable (s3:ListBucket on the bucket ARN).
- Always inspect getPrevious() on checksum failures instead of string-matching the top message only.
- Add jittered retries for transient network causes, keyed off the previous exception type.
When it happens
Trigger: $filesystem->checksum() / $adapter->checksum() on a nonexistent key, a key that is a directory marker, when the IAM policy denies s3:GetObject, when the SDK client has stale credentials or a wrong region, or when a filesystem path prefix maps to a missing S3 prefix.
Common situations: Key casing or prefix mistakes; environments with scoped-down IAM roles; cross-region misconfigurations producing 301/400 HeadObject errors; checksum verification after a concurrent delete or overwrite.
Related errors
- Unable to get checksum for $path: $reason
- ETag header not available.
- Unable to get checksum for $path: $reason
- Unable to get checksum for $path: $reason
- Unable to get checksum for $path: $reason
AI-assisted analysis of thephpleague/flysystem@b277b5dc3d (2026-08-17).
Data as JSON: /api/errors/a250969a7a5ce04e.
Report an issue: GitHub.