{"record":{"id":"a250969a7a5ce04e","repo":"thephpleague/flysystem","slug":"unable-to-get-checksum-for-path-reason-a25096","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/AwsS3V3/AwsS3V3Adapter.php","lineNumber":499,"sourceCode":"        try {\n            return $this->client->getObjectUrl($this->bucket, $location);\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            $options = $config->get('get_object_options', []);\n            $command = $this->client->getCommand('GetObject', [\n                    'Bucket' => $this->bucket,\n                    'Key' => $this->prefixer->prefixPath($path),\n                ] + $options);\n","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/thephpleague/flysystem/blob/b277b5dc3d56650b68904117124e79c851e12376/src/AwsS3V3/AwsS3V3Adapter.php#L481-L517","documentation":"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.","triggerScenarios":"$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.","commonSituations":"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.","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."],"exampleFix":"// before\n$etag = $filesystem->checksum('uploads/' . $id . '.zip'); // wrong id -> 404 -> throws\n\n// after\ntry {\n    $etag = $filesystem->checksum('uploads/' . $id . '.zip');\n} catch (UnableToProvideChecksum $e) {\n    $previous = $e->getPrevious();\n    if ($previous instanceof UnableToRetrieveMetadata && str_contains($previous->message(), '404')) {\n        return new NotFoundResponse($id);\n    }\n    throw $e;\n}","handlingStrategy":"try-catch","validationCode":"if ( ! $filesystem->fileExists($path)) {\n    // treat as missing artifact before attempting a HEAD-based checksum\n    return $fallback ?: throw new DomainException(\"Artifact not found: {$path}\");\n}","typeGuard":null,"tryCatchPattern":"use League\\Flysystem\\UnableToProvideChecksum;\n\ntry {\n    $etag = $filesystem->checksum($path);\n} catch (UnableToProvideChecksum $e) {\n    $previous = $e->getPrevious();               // UnableToRetrieveMetadata\n    $reason = $previous?->getMessage() ?? $e->getMessage();\n    if (str_contains($reason, '404') || str_contains($reason, 'NotFound')) {\n        return $onMissing($path);\n    }\n    if (str_contains($reason, '403') || str_contains($reason, 'AccessDenied')) {\n        return $onForbidden($path);\n    }\n    throw $e; // transport/unknown: retryable at a higher level\n}","preventionTips":["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."],"tags":["php","flysystem","aws-s3","aws-sdk-php","checksum","not-found","permissions"],"backgroundTag":"checksum-retrieval-failed","analyzedSha":"b277b5dc3d56650b68904117124e79c851e12376","analyzedAt":"2026-08-17T04:28:35.741Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}