{"record":{"id":"e8409767c9af5b62","repo":"BigPizzaV3/CodexPlusPlus","slug":"unsupported-native-browser-service-hash","errorCode":null,"errorMessage":"Unsupported native browser service hash","messagePattern":"Unsupported native browser service hash","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":255,"sourceCode":"                    PCWSTR(target.as_ptr()),\n                    MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH,\n                )\n            }\n            .map_err(anyhow::Error::from)\n        }\n        #[cfg(not(windows))]\n        {\n            fs::rename(&temp, path).map_err(anyhow::Error::from)\n        }\n    })();\n    if result.is_err() {\n        let _ = fs::remove_file(&temp);\n    }\n    result\n}\n\nfn transform(source: &[u8], control: &Path, contract: &RuntimeContract) -> Result<Vec<u8>> {\n    ensure!(\n        sha(source) == contract.service_sha,\n        \"Unsupported native browser service hash\"\n    );\n    transform_binding(source, control)\n}\n\nfn transform_binding(source: &[u8], control: &Path) -> Result<Vec<u8>> {\n    let text = std::str::from_utf8(source)?;\n    ensure!(\n        text.matches(ANCHOR).count() == 1,\n        \"Expected one callback binding\"\n    );\n    ensure!(\n        !text.contains(\"cppNativeIdentificationReader\"),\n        \"Conflicting adapter\"\n    );\n    let path = serde_json::to_string(&control.to_str().context(\"Non-Unicode control path\")?)?;\n    let replacement = format!(","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L237-L273","documentation":"transform only patches browser-service.mjs when its SHA-256 hash matches the pinned expected hash in the RuntimeContract (originally ORIGINAL_SHA). The library performs exact string surgery on a minified third-party bundle (ANCHOR replacement), which is only safe for the exact known build. If the source bytes hash to anything else — a different Codex version, an already-patched file, or a locally modified file — it refuses to transform.","triggerScenarios":"Running prepare after a Codex update changed browser-service.mjs (hash no longer matches ORIGINAL_SHA); running prepare twice, so the file already contains the injected helper; any manual edit or third-party modification of browser-service.mjs; the contract's service_sha pointing at a hash the runtime doesn't ship.","commonSituations":"Upstream Codex released a new version with a rebuilt minified bundle; a prior patch was not restored before re-running prepare (double-patching); the user edited the service script; a corporate security agent modified the file.","solutions":["Restore the original unpatched browser-service.mjs (run the library's restore path or reinstall/repair Codex), then run prepare once — the hash must match the pristine upstream build.","Check whether the file is already patched (`grep cppNativeIdentificationReader browser-service.mjs`); if so, restore first instead of patching again.","If a new Codex version legitimately changed the file, update the fork's pinned ANCHOR/ORIGINAL_SHA constants in native_browser.rs to match the new build, verify ANCHOR occurs exactly once, and bump the contract.","Verify the hash manually (Get-FileHash / sha256sum) against the pinned value to confirm which mismatch case you're in before changing anything."],"exampleFix":"// before: double-patched file fails hash check\nbrowser-service.mjs sha = a1b2... (contains helper)\n// after: restore pristine upstream file, then patch once\ncargo run -- restore-all && cargo run -- prepare","handlingStrategy":"validation","validationCode":"use sha2::{Digest, Sha256};\nfn sha256_hex(path: &Path) -> std::io::Result<String> {\n    let bytes = std::fs::read(path)?;\n    Ok(format!(\"{:x}\", Sha256::digest(&bytes)))\n}\nconst ORIGINAL_SHA: &str = \"3e6fd4a8cf09f57549d63f2c9cbfa2abf42f0a6b0c09c3d6605fe07c8ba09e4a\";\n// before calling prepare:\n// assert_eq!(sha256_hex(service_path)?, ORIGINAL_SHA, \"restore pristine browser-service.mjs first\");\n// and ensure it is not already patched:\n// assert!(!std::fs::read_to_string(service_path)?.contains(\"cppNativeIdentificationReader\"));","typeGuard":"fn is_pristine_service(path: &Path) -> bool {\n    match (std::fs::read(path), sha256_hex(path)) {\n        (Ok(_), Ok(h)) => h == ORIGINAL_SHA,\n        _ => false,\n    }\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"Unsupported native browser service hash\") => {\n        eprintln!(\"browser-service.mjs differs from the pinned build; restore it from a clean install or update the pinned hash: {e}\");\n    }\n    Err(e) => return Err(e.into()),\n    Ok(patched) => write_output(patched),\n}","preventionTips":["Always restore (restore_all) before re-running prepare to avoid double-patching","After a Codex upgrade, expect this error and re-derive ANCHOR/ORIGINAL_SHA from the new build before patching","Record the sha256 of the pristine service file and verify it before each automation run","Never hand-edit browser-service.mjs; treat it as an immutable build artifact"],"tags":["hash-mismatch","integrity","versioning","patching"],"backgroundTag":"checksum-mismatch","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}