{"record":{"id":"6e37a4dbff037005","repo":"diem/diem","slug":"found-modules-locally-but-in-remote-stor","errorCode":null,"errorMessage":"Found {:?} modules locally but {:?} in remote storage","messagePattern":"Found (.+?) modules locally but (.+?) in remote storage","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"language/diem-tools/writeset-transaction-generator/src/release_flow/verify.rs","lineNumber":136,"sourceCode":"                        Ok(m) => m,\n                        Err(e) => bail!(\"Unexpected module deserialize error {:?}\", e),\n                    };\n\n                    match old_modules.insert(module_id.clone(), updated_module.clone()) {\n                        Some(_) => println!(\"Updating existing module: {:?}\", module_id),\n                        None => println!(\"Adding new module: {:?}\", module_id),\n                    }\n                }\n            }\n        }\n    }\n\n    let local_modules = remote_modules\n        .into_iter()\n        .map(|m| (m.self_id(), m.clone()))\n        .collect::<BTreeMap<_, _>>();\n    if local_modules.len() != old_modules.len() {\n        bail!(\n            \"Found {:?} modules locally but {:?} in remote storage\",\n            local_modules.len(),\n            old_modules.len()\n        )\n    }\n    for (remote, local) in old_modules.values().zip(local_modules.values()) {\n        if remote != local {\n            bail!(\"Applying writeset onto the state causes module {:?} diverge from the on disk files\", local.self_id())\n        }\n    }\n    Ok(())\n}\n","sourceCodeStart":118,"sourceCodeEnd":149,"githubUrl":"https://github.com/diem/diem/blob/fc4714a8ea273b6efe8b13dbce72ea60aad9a16c/language/diem-tools/writeset-transaction-generator/src/release_flow/verify.rs#L118-L149","documentation":"After applying the writeset, the resulting module set (old_modules) must contain exactly as many modules as the local artifact (remote_modules). A count mismatch means the writeset adds or removes a different number of modules than the artifact carries, so post-state cannot equal the on-disk release.","triggerScenarios":"verify_payload_change compares local_modules.len() vs old_modules.len(); mismatch occurs when the payload publishes/deletes modules not accounted for by the artifact — e.g. artifact missing a newly added module, or payload including extra modules.","commonSituations":"Release artifact directory incomplete (missing new modules); payload generated from a different artifact version; dependency modules expected to change but absent; replay against a chain version with different module count.","solutions":["Ensure the artifact directory contains every module the writeset publishes or updates","Regenerate the writeset payload from the same complete artifact","Replay against a chain state consistent with the release prerequisites"],"exampleFix":"// before\nartifact_dir/standard/  // missing new module X.mv\n// after\nartifact_dir/standard/  // includes X.mv so counts match","handlingStrategy":"validation","validationCode":"fn module_counts_match(artifact_modules: &[CompiledModule], old_modules: &BTreeMap<ModuleId, CompiledModule>) -> bool {\n    artifact_modules.len() == old_modules.len()\n}","typeGuard":null,"tryCatchPattern":"match verify_payload_change(...) {\n    Err(e) if e.to_string().contains(\"modules locally but\") => {\n        eprintln!(\"Artifact vs chain module count mismatch; regenerate payload from complete artifact\");\n    }\n    other => other?,\n}","preventionTips":["Verify the artifact directory includes every module the release adds or changes","Regenerate payload and artifact together in one release pipeline","Snapshot the chain's module set and diff against the artifact before creating the payload"],"tags":["modules","count-mismatch","release"],"backgroundTag":"module-count-mismatch","analyzedSha":"fc4714a8ea273b6efe8b13dbce72ea60aad9a16c","analyzedAt":"2026-09-04T21:07:05.890Z","contentChangedAt":"2026-09-04T21:07:05.890Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}