{"record":{"id":"636dcb3e5ebf70eb","repo":"pnpm/pnpm","slug":"failed-to-read-the-manifest-of-a-workspace-root-de","errorCode":null,"errorMessage":"Failed to read the manifest of a workspace root dependency: {_0}","messagePattern":"Failed to read the manifest of a workspace root dependency: (.+?)","errorType":"exception","errorClass":"InstallWithFreshLockfileError","httpStatus":null,"severity":"error","filePath":"pnpm/crates/package-manager/src/install_with_fresh_lockfile.rs","lineNumber":484,"sourceCode":"    LinkVirtualStoreBins(#[error(source)] LinkVirtualStoreBinsError),\n\n    /// The resolver chain failed for at least one dependency. The\n    /// diagnostic is forwarded transparently so a canonical inner code\n    /// (e.g. a traversal name's `ERR_PNPM_INVALID_DEPENDENCY_NAME`)\n    /// reaches the CLI unchanged. The `Display` still interpolates the\n    /// inner error so consumers that stringify the top-level error\n    /// (e.g. pnpr's `resolve.rs`, which forwards `err.to_string()` over\n    /// the wire) keep the detail.\n    #[display(\"Failed to resolve dependency tree: {_0}\")]\n    #[diagnostic(transparent)]\n    ResolveDependencyTree(#[error(source)] ResolveDependencyTreeError),\n\n    /// Surfaces a failure to read the manifest of a workspace-root\n    /// `link:` / `file:` dependency, whose version stands in for the peer\n    /// it may satisfy under `resolvePeersFromWorkspaceRoot`.\n    #[display(\"Failed to read the manifest of a workspace root dependency: {_0}\")]\n    #[diagnostic(transparent)]\n    RootDepManifest(#[error(source)] pnpm_package_manifest::PackageManifestError),\n\n    #[display(\"Failed to build lockfile from resolved dependency graph: {_0}\")]\n    #[diagnostic(code(pnpm_package_manager::dependencies_graph_to_lockfile))]\n    DependenciesGraphToLockfile(#[error(source)] Box<DependenciesGraphToLockfileError>),\n\n    /// `minimumReleaseAgeExclude` patterns rejected at compile time.\n    /// Surfaced as `ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE`.\n    #[display(\"Invalid value in minimumReleaseAgeExclude: {_0}\")]\n    #[diagnostic(code(ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE))]\n    MinimumReleaseAgeExclude(#[error(source)] pnpm_config::version_policy::VersionPolicyError),\n\n    /// `trustPolicyExclude` patterns rejected at compile time.\n    /// Surfaced as `ERR_PNPM_INVALID_TRUST_POLICY_EXCLUDE`.\n    #[display(\"Invalid value in trustPolicyExclude: {_0}\")]\n    #[diagnostic(code(ERR_PNPM_INVALID_TRUST_POLICY_EXCLUDE))]\n    TrustPolicyExclude(#[error(source)] pnpm_config::version_policy::VersionPolicyError),\n\n    /// `allowBuilds` patterns in `pnpm-workspace.yaml` couldn't be","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/pnpm/pnpm/blob/6261b7f388016d57ca6b90340342411cd1d0d00f/pnpm/crates/package-manager/src/install_with_fresh_lockfile.rs#L466-L502","documentation":"InstallWithFreshLockfileError::RootDepManifest wraps a PackageManifestError raised while reading the manifest of a workspace-root link:/file: dependency. Pacquet reads it because, under resolvePeersFromWorkspaceRoot, the root dependency's version can stand in for a peer it may satisfy; if that manifest cannot be read, the fresh install fails.","triggerScenarios":"A root package.json dependency such as link:./local or file:./pkg whose target directory has no package.json, contains malformed JSON, or does not exist — with resolvePeersFromWorkspaceRoot in effect.","commonSituations":"Sibling workspace packages linked before being initialized (no package.json yet), moved or renamed local packages leaving stale link: entries, hand-written malformed manifests.","solutions":["Ensure every root link:/file: target contains a valid package.json with name and version","Fix or remove stale link: entries that point at deleted or moved directories","If peer satisfaction from the root is not needed, disable resolvePeersFromWorkspaceRoot"],"exampleFix":"# before (root package.json): \"my-ui\": \"link:./packages/my-ui\" but packages/my-ui/package.json is missing\n# after: create packages/my-ui/package.json\n{\n  \"name\": \"my-ui\",\n  \"version\": \"1.0.0\"\n}","handlingStrategy":"validation","validationCode":"// Verify every root link:/file: target has a readable manifest before install\nfor (name, spec) in &root_manifest.dependencies {\n    if let Some(path) = spec.strip_prefix(\"link:\").or_else(|| spec.strip_prefix(\"file:\")) {\n        let manifest = std::path::Path::new(path).join(\"package.json\");\n        let parsed: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(manifest)?)?;\n        assert!(parsed.get(\"name\").is_some() && parsed.get(\"version\").is_some());\n    }\n}","typeGuard":"fn is_root_dep_manifest_error(err: &InstallWithFreshLockfileError) -> bool {\n    matches!(err, InstallWithFreshLockfileError::RootDepManifest(_))\n}","tryCatchPattern":"match fresh_install().await {\n    Err(err @ InstallWithFreshLockfileError::RootDepManifest(_)) => {\n        // list root link:/file: deps and check each target for a valid package.json\n    }\n    result => result?,\n}","preventionTips":["Initialize a package.json (name + version) in every locally linked package before linking it","Update link: paths immediately when moving or renaming local packages","Run a repo lint that resolves all link: targets to existing manifests"],"tags":["workspace","link-dependencies","package-json","peers","manifest"],"backgroundTag":"missing-package-json","analyzedSha":"6261b7f388016d57ca6b90340342411cd1d0d00f","analyzedAt":"2026-08-17T18:30:54.750Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}