{"record":{"id":"9731eaa61b01bc37","repo":"symfony/http-kernel","slug":"x-body-file-and-x-content-digest-do-not-match","errorCode":null,"errorMessage":"X-Body-File and X-Content-Digest do not match.","messagePattern":"X-Body-File and X-Content-Digest do not match\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"HttpCache/Store.php","lineNumber":191,"sourceCode":"     * Existing entries are read and any that match the response are removed. This\n     * method calls write with the new list of cache entries.\n     *\n     * @throws \\RuntimeException\n     */\n    public function write(Request $request, Response $response): string\n    {\n        $key = $this->getCacheKey($request);\n        $storedEnv = $this->persistRequest($request);\n\n        if ($response->headers->has('X-Body-File')) {\n            // Assume the response came from disk, but at least perform some safeguard checks\n            if (!$response->headers->has('X-Content-Digest')) {\n                throw new \\RuntimeException('A restored response must have the X-Content-Digest header.');\n            }\n\n            $digest = $response->headers->get('X-Content-Digest');\n            if ($this->getPath($digest) !== $response->headers->get('X-Body-File')) {\n                throw new \\RuntimeException('X-Body-File and X-Content-Digest do not match.');\n            }\n        // Everything seems ok, omit writing content to disk\n        } else {\n            // Responses that cannot provide their content, like BinaryFileResponse or\n            // StreamedResponse, have no entity to store, so no entry is written\n            if (false === $content = $response->getContent()) {\n                return $key;\n            }\n\n            $digest = $this->generateContentDigest($response);\n            $response->headers->set('X-Content-Digest', $digest);\n\n            if (!$this->save($digest, $content, false)) {\n                throw new \\RuntimeException('Unable to store the entity.');\n            }\n\n            if (!$response->headers->has('Transfer-Encoding')) {\n                $response->headers->set('Content-Length', \\strlen($content));","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/symfony/http-kernel/blob/aa3a39d7286a62cdfea98f0e69c651a3da6e36cf/HttpCache/Store.php#L173-L209","documentation":"When a response being written to the HttpCache store already has an X-Body-File header, Store::write() verifies that the body file path matches the path recomputed from the X-Content-Digest header. A mismatch means the digest and body-file headers disagree, so the response cannot safely be re-stored and the RuntimeException is thrown to prevent writing metadata pointing at the wrong body.","triggerScenarios":"Store::write() with a response whose X-Content-Digest maps (via getPath()) to a different file path than the X-Body-File header value — typically a restored response whose internal headers were edited or mixed between cache entries.","commonSituations":"Copying cached responses between cache directories so digests no longer match paths; merging headers from two different cached responses; tampering with X-Content-Digest or X-Body-File in tests or custom stores.","solutions":["Regenerate both internal headers together by calling Store::restore() or by removing X-Body-File/X-Content-Digest and letting write() recompute them","Clear the HTTP cache so all entries are rebuilt consistently","Fix custom code that copies X-Content-Digest from one entry with X-Body-File of another"],"exampleFix":"// before\n$response->headers->set('X-Content-Digest', $oldDigest);\n$response->headers->set('X-Body-File', $newPath);\n// after\n$response->headers->remove('X-Content-Digest');\n$response->headers->remove('X-Body-File');\n$store->write($request, $response); // store generates a consistent digest+path pair","handlingStrategy":"validation","validationCode":"if ($response->headers->has('X-Body-File') && $response->headers->has('X-Content-Digest')\n    && $digest !== $response->headers->get('X-Content-Digest')) {\n    $response->headers->remove('X-Body-File');\n    $response->headers->remove('X-Content-Digest');\n}\n$store->write($request, $response);","typeGuard":null,"tryCatchPattern":"try {\n    $store->write($request, $response);\n} catch (\\RuntimeException $e) {\n    // fall back to a clean response without internal cache headers\n    $response->headers->remove('X-Body-File');\n    $response->headers->remove('X-Content-Digest');\n    $store->write($request, $response);\n}","preventionTips":["Keep digest and body-file headers as an atomic pair","Do not copy responses across cache directories","Clear the cache instead of patching entries"],"tags":["http-cache","cache-consistency","symfony"],"backgroundTag":"checksum-mismatch","analyzedSha":"aa3a39d7286a62cdfea98f0e69c651a3da6e36cf","analyzedAt":"2026-09-13T18:03:36.509Z","contentChangedAt":"2026-09-13T18:03:36.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}