{"record":{"id":"075487260ff03ec3","repo":"jdx/mise","slug":"invalid-dependency-graph-digest","errorCode":null,"errorMessage":"invalid dependency graph digest","messagePattern":"invalid dependency graph digest","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lockfile/graph.rs","lineNumber":158,"sourceCode":"            *dir = absolute(lockfile.parent().unwrap_or(Path::new(\".\"))).join(&*dir);\n        }\n        Ok(())\n    }\n    pub(crate) fn parse(value: toml::Value) -> Result<Self> {\n        if value.get(\"path\").is_some() {\n            #[derive(Deserialize)]\n            #[serde(deny_unknown_fields)]\n            struct Pointer {\n                path: PathBuf,\n                digest: String,\n            }\n            let p: Pointer = value.try_into()?;\n            if !p\n                .digest\n                .strip_prefix(\"sha256:\")\n                .is_some_and(|s| s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit()))\n            {\n                bail!(\"invalid dependency graph digest\");\n            }\n            Ok(Self::Sidecar {\n                dir: p.path,\n                digest: p.digest,\n                cell: OnceLock::new(),\n            })\n        } else {\n            debug!(\n                \"migrating inline dependency graph to a native sidecar on the next lockfile save\"\n            );\n            Ok(Self::from(value.try_into::<T>()?))\n        }\n    }\n    pub(crate) fn pointer(&self, base: &Path) -> Result<toml::Value> {\n        let dir = self\n            .dir()\n            .ok_or_else(|| eyre!(\"dependency sidecar has not been prepared\"))?;\n        let relative = dir.strip_prefix(absolute(base))?;","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/lockfile/graph.rs#L140-L176","documentation":"When parsing a dependency-graph pointer from the lockfile, the `digest` must be a `sha256:`-prefixed, exactly-64-hex-character value. `GraphRef::parse` bails otherwise, because the digest is used to detect tampering/unexpected changes in the sidecar dependency graph.","triggerScenarios":"Loading a lockfile whose dependency entry has a missing, empty, non-sha256, or wrong-length digest — e.g. `digest = \"abc123\"`, `digest = \"sha256:xyz\"`, or a digest computed with a different algorithm pasted in.","commonSituations":"Hand-edited lockfiles; digests generated by other tooling (sha512, md5); truncated digests from copy/paste; older lockfile formats without proper digests.","solutions":["Set the digest to the correct `sha256:<64 hex chars>` of the sidecar dependency graph file","Regenerate the lockfile so the digest is recomputed automatically","Remove any hand edits and re-lock from a clean state","Verify with `sha256sum` that the recorded digest matches the sidecar file"],"exampleFix":"# before\ndigest = \"e3b0c442\"\n# after\ndigest = \"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"","handlingStrategy":"validation","validationCode":"fn valid_sha256_digest(d: &str) -> bool {\n    d.strip_prefix(\"sha256:\")\n        .is_some_and(|s| s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit()))\n}","typeGuard":"fn is_sha256_digest(s: &str) -> bool {\n    s.strip_prefix(\"sha256:\")\n        .is_some_and(|h| h.len() == 64 && h.bytes().all(|b| b.is_ascii_hexdigit()))\n}","tryCatchPattern":null,"preventionTips":["Always compute digests with SHA-256 and include the `sha256:` prefix","Never truncate digests when copy/pasting","Regenerate lockfiles rather than editing digests by hand","Verify digests with `sha256sum` after external tooling writes lockfiles"],"tags":["lockfile","digest","sha256","validation"],"backgroundTag":"checksum-mismatch","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}