{"record":{"id":"f853a3c0aa2cd944","repo":"thephpleague/flysystem","slug":"no-checksum-provided-in-metadata","errorCode":null,"errorMessage":"No checksum provided in metadata","messagePattern":"No checksum provided in metadata","errorType":"exception","errorClass":"UnableToProvideChecksum","httpStatus":null,"severity":"error","filePath":"src/AzureBlobStorage/AzureBlobStorageAdapter.php","lineNumber":366,"sourceCode":"    }\n\n    public function checksum(string $path, Config $config): string\n    {\n        $algo = $config->get('checksum_algo', 'md5');\n\n        if ($algo !== 'md5') {\n            throw new ChecksumAlgoIsNotSupported();\n        }\n\n        try {\n            $metadata = $this->fetchMetadata($this->prefixer->prefixPath($path));\n            $checksum = $metadata->extraMetadata()['md5_checksum'] ?? '__not_specified';\n        } catch (Throwable $exception) {\n            throw new UnableToProvideChecksum($exception->getMessage(), $path, $exception);\n        }\n\n        if ($checksum === '__not_specified') {\n            throw new UnableToProvideChecksum('No checksum provided in metadata', $path);\n        }\n\n        return bin2hex(base64_decode($checksum));\n    }\n\n    public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string\n    {\n        if ( ! $this->serviceSettings instanceof StorageServiceSettings) {\n            throw UnableToGenerateTemporaryUrl::noGeneratorConfigured(\n                $path,\n                'The $serviceSettings constructor parameter must be set to generate temporary URLs.',\n            );\n        }\n\n        try {\n            $sas = new BlobSharedAccessSignatureHelper($this->serviceSettings->getName(), $this->serviceSettings->getKey());\n            $baseUrl = $this->publicUrl($path, $config);\n            $resourceName = $this->container . '/' . ltrim($this->prefixer->prefixPath($path), '/');","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/thephpleague/flysystem/blob/b277b5dc3d56650b68904117124e79c851e12376/src/AzureBlobStorage/AzureBlobStorageAdapter.php#L348-L384","documentation":"AzureBlobStorageAdapter::checksum() found the blob and read its properties, but the md5_checksum extra field is absent, meaning Content-MD5 was not stored on the blob. Azure only populates Content-MD5 when it was set at upload time (or the client computed it), so many blobs written without that header have no retrievable checksum, and Flysystem refuses to invent one.","triggerScenarios":"Calling checksum() on a blob uploaded without a Content-MD5 header — typical when the blob was written by third-party tools, azcopy defaults, Put Blob calls from other SDKs, or Flysystem's own write() (which does not set Content-MD5). Also blobs whose MD5 was never populated server-side.","commonSituations":"Migrating pre-existing data into checksum-verified pipelines; mixed writers (some set Content-MD5, some don't); assuming Azure computes MD5 automatically like S3 does ETag.","solutions":["Re-upload (or re-write via Put Blob/Copy) the object with the Content-MD5 header set to the base64 md5 of the content.","Or compute the digest client-side: hash $filesystem->readStream($path) with hash_init('md5')/hash_update_stream — Filesystem::checksum() with 'checksum_algo' left at its md5 default only helps if the adapter is bypassed.","Audit writers so every upload sets Content-MD5 (Azure SDK setMetadata/contentMd6 option or 'Content-MD5' header on createBlockBlob).","Catch UnableToProvideChecksum and treat 'No checksum provided in metadata' as a data-quality signal to repair the blob."],"exampleFix":"// before\n$checksum = $azureAdapter->checksum('legacy/file.dat', new Config()); // blob has no Content-MD5 -> throws\n\n// after (compute from stream when stored MD5 is absent)\ntry {\n    $checksum = $azureAdapter->checksum('legacy/file.dat', new Config());\n} catch (UnableToProvideChecksum $e) {\n    $stream = $filesystem->readStream('legacy/file.dat');\n    $ctx = hash_init('md5');\n    hash_update_stream($ctx, $stream);\n    $checksum = hash_final($ctx);\n    // optionally repair: re-upload with 'Content-MD5' => base64_encode(hex2bin($checksum))\n}","handlingStrategy":"fallback","validationCode":"// There is no reliable pre-check for stored Content-MD5 other than fetching metadata:\ntry {\n    $md5 = $adapter->checksum($path, new Config());\n} catch (UnableToProvideChecksum $e) {\n    // handled below\n}\n// For new uploads, set Content-MD5 at write time so this path never triggers:\n$filesystem->write($path, $contents, ['headers' => ['Content-MD5' => base64_encode(pack('H*', md5($contents)))]]);","typeGuard":null,"tryCatchPattern":"use League\\Flysystem\\UnableToProvideChecksum;\n\ntry {\n    $md5 = $filesystem->checksum($path);\n} catch (UnableToProvideChecksum $e) {\n    if (str_contains($e->getMessage(), 'No checksum provided in metadata')) {\n        // blob has no stored Content-MD5: compute it and repair the blob\n        $stream = $filesystem->readStream($path);\n        $ctx = hash_init('md5');\n        hash_update_stream($ctx, $stream);\n        $md5 = hash_final($ctx);\n        $filesystem->write($path, stream_get_contents($stream), [\n            'headers' => ['Content-MD5' => base64_encode(hex2bin($md5))],\n        ]);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Set Content-MD5 on every upload your application performs to Azure.","Backfill legacy blobs with a one-off job that computes and re-writes MD5 metadata.","Treat 'No checksum provided in metadata' as a data-quality incident, not a transient error."],"tags":["php","flysystem","azure-blob-storage","checksum","content-md5","missing-metadata"],"backgroundTag":"missing-content-md5","analyzedSha":"b277b5dc3d56650b68904117124e79c851e12376","analyzedAt":"2026-08-17T04:28:35.741Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}