{"record":{"id":"c74f56ac341be6e6","repo":"thephpleague/flysystem","slug":"unable-to-get-checksum-for-path-reason","errorCode":null,"errorMessage":"Unable to get checksum for $path: $reason","messagePattern":"Unable to get checksum for \\$path: \\$reason","errorType":"exception","errorClass":"UnableToProvideChecksum","httpStatus":null,"severity":"error","filePath":"src/AsyncAwsS3/AsyncAwsS3Adapter.php","lineNumber":565,"sourceCode":"        try {\n            return $this->client->getUrl($this->bucket, $this->prefixer->prefixPath($path));\n        } catch (Throwable $exception) {\n            throw UnableToGeneratePublicUrl::dueToError($path, $exception);\n        }\n    }\n\n    public function checksum(string $path, Config $config): string\n    {\n        $algo = $config->get('checksum_algo', 'etag');\n\n        if ($algo !== 'etag') {\n            throw new ChecksumAlgoIsNotSupported();\n        }\n\n        try {\n            $metadata = $this->fetchFileMetadata($path, 'checksum')->extraMetadata();\n        } catch (UnableToRetrieveMetadata $exception) {\n            throw new UnableToProvideChecksum($exception->reason(), $path, $exception);\n        }\n\n        if ( ! isset($metadata['ETag'])) {\n            throw new UnableToProvideChecksum('ETag header not available.', $path);\n        }\n\n        return trim($metadata['ETag'], '\"');\n    }\n\n    public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string\n    {\n        try {\n            $request = new GetObjectRequest([\n                'Bucket' => $this->bucket,\n                'Key' => $this->prefixer->prefixPath($path),\n            ] + $config->get('get_object_options', []));\n\n            return $this->client->presign($request, DateTimeImmutable::createFromInterface($expiresAt));","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/thephpleague/flysystem/blob/b277b5dc3d56650b68904117124e79c851e12376/src/AsyncAwsS3/AsyncAwsS3Adapter.php#L547-L583","documentation":"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.","triggerScenarios":"$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.","commonSituations":"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.","solutions":["Verify the path exists first with $filesystem->fileExists($path) and handle the race window gracefully.","Inspect $exception->getPrevious() to find the real cause (404, 403, DNS, credentials) and fix that.","For permission errors, grant s3:GetObject (and s3:ListBucket on the bucket) to the credentials used by the AsyncAws S3Client.","Catch UnableToProvideChecksum at the call site and retry or degrade, since transient network errors surface here too."],"exampleFix":"// before\n$checksum = $filesystem->checksum('reports/2024/q1.csv'); // file was deleted -> throws\n\n// after\nif ( ! $filesystem->fileExists('reports/2024/q1.csv')) {\n    throw new RuntimeException('Report missing, cannot verify integrity.');\n}\n\ntry {\n    $checksum = $filesystem->checksum('reports/2024/q1.csv', ['checksum_algo' => 'etag']);\n} catch (UnableToProvideChecksum $e) {\n    $reason = $e->getPrevious() ? $e->getPrevious()->getMessage() : $e->getMessage();\n    // handle 403 (permissions), 404 (raced delete), network errors\n}","handlingStrategy":"try-catch","validationCode":"if ( ! $filesystem->fileExists($path)) {\n    throw new InvalidArgumentException(\"Cannot checksum missing path: {$path}\");\n}\n// fileExists uses HeadObject, so permission problems surface there with clearer context","typeGuard":null,"tryCatchPattern":"use League\\Flysystem\\UnableToProvideChecksum;\n\ntry {\n    $etag = $filesystem->checksum($path);\n} catch (UnableToProvideChecksum $e) {\n    $previous = $e->getPrevious();\n    // branch on the wrapped UnableToRetrieveMetadata reason (404 vs 403 vs network)\n    log_warning('checksum failed', ['path' => $path, 'reason' => $e->getMessage()]);\n    throw $e;\n}","preventionTips":["Grant the client IAM permission for HeadObject (s3:GetObject + s3:ListBucket) so 404s are distinguishable from 403s.","Run fileExists() before checksumming when the file's presence is not guaranteed.","In retry policies, retry only when the chained exception indicates a transport error, not 404/403."],"tags":["php","flysystem","s3","async-aws","checksum","metadata","not-found"],"backgroundTag":"checksum-retrieval-failed","analyzedSha":"b277b5dc3d56650b68904117124e79c851e12376","analyzedAt":"2026-08-17T04:28:35.741Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}