{"record":{"id":"df5f2b732afb041a","repo":"Hmbown/CodeWhale","slug":"plugin-source-changed-after-review-expected-conte","errorCode":null,"errorMessage":"plugin source changed after review: expected content hash {expected}, copied bytes hash is {actual}; nothing was installed","messagePattern":"plugin source changed after review: expected content hash (.+?), copied bytes hash is (.+?); nothing was installed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/plugins/install/mod.rs","lineNumber":343,"sourceCode":"                expected_content_hash,\n            )\n        }\n    }\n}\n\nfn verify_expected_content_hash(\n    staged: &stage::StagedPlugin,\n    expected_content_hash: Option<&str>,\n) -> Result<()> {\n    let Some(expected) = expected_content_hash else {\n        return Ok(());\n    };\n    if staged.content_hash == expected {\n        return Ok(());\n    }\n    let actual = staged.content_hash.clone();\n    let _ = fs::remove_dir_all(&staged.staged_path);\n    bail!(\n        \"plugin source changed after review: expected content hash {expected}, copied bytes hash is {actual}; nothing was installed\"\n    )\n}\n\n/// Stage and finalize an already-downloaded remote tarball. Kept separate\n/// from [`install`] so [`update`] can compare the checksum of the bytes it\n/// already fetched instead of downloading twice.\n#[allow(clippy::too_many_arguments)]\nfn install_remote_bytes(\n    remote: &InstallSource,\n    bytes: &[u8],\n    url: &str,\n    user_plugins_dir: &Path,\n    max_size: u64,\n    update: bool,\n    name_conflict: &dyn Fn(&str) -> Option<String>,\n    expected_content_hash: Option<&str>,\n) -> Result<PluginInstallOutcome> {","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/plugins/install/mod.rs#L325-L361","documentation":"verify_expected_content_hash compared the staged copy's content hash against the hash recorded at review time and found a mismatch — the source changed between user review and installation. The staged copy is deleted and nothing is installed, guaranteeing only reviewed bytes land in the plugins directory.","triggerScenarios":"Thrown at crates/tui/src/plugins/install/mod.rs:343 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Re-review the plugin (its content genuinely changed)","Then reinstall with the updated expected hash"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}