BigPizzaV3/CodexPlusPlus · error
Unsupported native browser service hash
Error message
Unsupported native browser service hash
What it means
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.
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.
Example fix
// before: double-patched file fails hash check browser-service.mjs sha = a1b2... (contains helper) // after: restore pristine upstream file, then patch once cargo run -- restore-all && cargo run -- prepare
Defensive patterns
Strategy: validation
Validate before calling
use sha2::{Digest, Sha256};
fn sha256_hex(path: &Path) -> std::io::Result<String> {
let bytes = std::fs::read(path)?;
Ok(format!("{:x}", Sha256::digest(&bytes)))
}
const ORIGINAL_SHA: &str = "3e6fd4a8cf09f57549d63f2c9cbfa2abf42f0a6b0c09c3d6605fe07c8ba09e4a";
// before calling prepare:
// assert_eq!(sha256_hex(service_path)?, ORIGINAL_SHA, "restore pristine browser-service.mjs first");
// and ensure it is not already patched:
// assert!(!std::fs::read_to_string(service_path)?.contains("cppNativeIdentificationReader")); Type guard
fn is_pristine_service(path: &Path) -> bool {
match (std::fs::read(path), sha256_hex(path)) {
(Ok(_), Ok(h)) => h == ORIGINAL_SHA,
_ => false,
}
} Try / catch
match result {
Err(e) if e.to_string().contains("Unsupported native browser service hash") => {
eprintln!("browser-service.mjs differs from the pinned build; restore it from a clean install or update the pinned hash: {e}");
}
Err(e) => return Err(e.into()),
Ok(patched) => write_output(patched),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/e8409767c9af5b62.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/native_browser.rs:255
PCWSTR(target.as_ptr()),
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH,
)
}
.map_err(anyhow::Error::from)
}
#[cfg(not(windows))]
{
fs::rename(&temp, path).map_err(anyhow::Error::from)
}
})();
if result.is_err() {
let _ = fs::remove_file(&temp);
}
result
}
fn transform(source: &[u8], control: &Path, contract: &RuntimeContract) -> Result<Vec<u8>> {
ensure!(
sha(source) == contract.service_sha,
"Unsupported native browser service hash"
);
transform_binding(source, control)
}
fn transform_binding(source: &[u8], control: &Path) -> Result<Vec<u8>> {
let text = std::str::from_utf8(source)?;
ensure!(
text.matches(ANCHOR).count() == 1,
"Expected one callback binding"
);
ensure!(
!text.contains("cppNativeIdentificationReader"),
"Conflicting adapter"
);
let path = serde_json::to_string(&control.to_str().context("Non-Unicode control path")?)?;
let replacement = format!(View on GitHub (pinned to b1ed92e5e4)