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

  1. 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.
  2. Check whether the file is already patched (`grep cppNativeIdentificationReader browser-service.mjs`); if so, restore first instead of patching again.
  3. 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.
  4. 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

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)