{"record":{"id":"089843902971e1ba","repo":"flarum/framework","slug":"cannot-read-the-installed-package-manifest-at-path-reason-089843","errorCode":null,"errorMessage":"Cannot read the installed package manifest at $path: $reason. Flarum cannot determine which extensions are installed until this is resolved, which usually means completing or re-running `composer install`. (the file is not valid JSON, so it may be corrupt or only partially written)","messagePattern":"Cannot read the installed package manifest at \\$path: \\$reason\\. Flarum cannot determine which extensions are installed until this is resolved, which usually means completing or re-running `composer install`\\. \\(the file is not valid JSON, so it may be corrupt or only partially written\\)","errorType":"exception","errorClass":"UnreadableManifestException","httpStatus":null,"severity":"critical","filePath":"framework/core/src/Extension/ExtensionManager.php","lineNumber":69,"sourceCode":"     * @return Collection<string, Extension>\n     */\n    public function getExtensions(): Collection\n    {\n        if (is_null($this->extensions)) {\n            $manifest = $this->paths->vendor.'/composer/installed.json';\n\n            if (! $this->filesystem->exists($manifest)) {\n                throw UnreadableManifestException::missing($manifest);\n            }\n\n            /** @var Collection<string, Extension> $extensions */\n            $extensions = new Collection();\n\n            // Load all packages installed by composer.\n            $installed = json_decode($this->filesystem->get($manifest), true);\n\n            if (! is_array($installed)) {\n                throw UnreadableManifestException::unparsable($manifest);\n            }\n\n            // Composer 2.0 changes the structure of the installed.json manifest\n            $installed = $installed['packages'] ?? $installed;\n\n            if (! is_array($installed)) {\n                throw UnreadableManifestException::unparsable($manifest);\n            }\n\n            // We calculate and store a set of composer package names for all installed Flarum extensions,\n            // so we know what is and isn't a flarum extension in `calculateDependencies`.\n            // Using keys of an associative array allows us to do these checks in constant time.\n            $installedSet = [];\n\n            $composerJsonConfs = [];\n\n            foreach ($installed as $package) {\n                $name = Arr::get($package, 'name');","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/framework/core/src/Extension/ExtensionManager.php#L51-L87","documentation":"After loading composer's installed.json, ExtensionManager checks json_decode result; a non-array means the manifest is not valid JSON, so UnreadableManifestException::unparsable() is thrown — the file exists but is corrupt, empty, or only partially written.","triggerScenarios":"getExtensions() reads {vendor}/composer/installed.json and json_decode returns null/scalar instead of an array (truncated write, concurrent composer run, disk-full, manual edits).","commonSituations":"Deploys interrupted mid-composer, two composer processes racing on the same install, corrupted artifacts, or files damaged by bad rsync/checkout.","solutions":["Re-run `composer install` to regenerate a valid installed.json","Delete the corrupt vendor/composer/installed.json and reinstall","Ensure only one composer process runs at a time during deploys","Validate the file: `php -r 'var_dump(is_array(json_decode(file_get_contents(\"vendor/composer/installed.json\"), true)));'`"],"exampleFix":"// before\n# installed.json truncated: '{\"packages\": ['\n// after\ncomposer install   # rewrites a valid installed.json","handlingStrategy":"try-catch","validationCode":"$data = json_decode(file_get_contents($vendor.'/composer/installed.json'), true);\nif (!is_array($data)) { /* regenerate before boot */ }","typeGuard":"function validManifest(string $vendor): bool {\n  $raw = @file_get_contents($vendor.'/composer/installed.json');\n  return is_array(json_decode($raw ?? '', true));\n}","tryCatchPattern":"try {\n    $extensions = $manager->getExtensions();\n} catch (UnreadableManifestException $e) {\n    logger()->critical('installed.json corrupt: rerun composer install');\n    abort(500);\n}","preventionTips":["Never run two composer processes against the same app concurrently","Use atomic deploys (build vendor in a temp dir, then symlink/swap)","Checksum installed.json in deploy verification","Keep composer install inside its own completed deploy step"],"tags":["composer","json","manifest","corrupt-file"],"backgroundTag":"json-decode-failed","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}