BigPizzaV3/CodexPlusPlus · error
Ambiguous runtime selection; no cache was modified
Error message
Ambiguous runtime selection; no cache was modified
What it means
After scanning all descriptors, discover() requires that at most one distinct runtime key was selected across every valid .mcp.json. If two or more descriptors select different runtime keys, Codex++ cannot tell which runtime cache to prepare, and per its safety contract it aborts without touching the cache ("no cache was modified").
Solutions
- Delete or fix the stale descriptor(s) so all remaining .mcp.json files select the same runtime key
- Remove the outdated runtime directory under the runtime root and its descriptor together, keeping only the current pair
- Reinstall the plugin to leave exactly one versioned descriptor directory
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
let mut keys = BTreeSet::new();
for dir in descriptor_dirs(&plugins) {
if let Ok(k) = selected_key(&read_descriptor(&dir)?, &runtime_root) { keys.insert(k); }
}
if keys.len() > 1 { eprintln!("descriptors select multiple runtimes: {keys:?}; remove stale ones"); } Try / catch
match discover(&paths) {
Err(e) if e.to_string().contains("Ambiguous runtime selection") => {
keep_only_newest_descriptor_dir(&plugins_cache)?; // remove stale version dirs, then retry
discover(&paths)
}
other => other,
} Prevention
- Install only one plugin version at a time; delete the old descriptor dir after upgrades
- Never copy .mcp.json descriptors between machines
- After failed upgrades, clean up leftover version directories before retrying
When it happens
Trigger: discover() collects selected_key results into a BTreeSet and keys.len() > 1 — i.e. at least two plugin descriptor directories contain .mcp.json files whose cua_repl commands/env point at different runtime keys (different runtime versions installed side by side).
Common situations: Two plugin versions installed concurrently after a failed cleanup; one descriptor pinned to an old runtime and another to a new one; a manually copied descriptor referencing another machine's runtime key.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Conflicting native worker selection
- Original browser service is not selected
- Too many plugin descriptors
- Unsupported native entry point
- Unsupported native surface selection
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/57c4821f0eb7268b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/native_browser.rs:360
return Ok(None);
}
let mut keys = BTreeSet::new();
let mut count = 0;
for entry in fs::read_dir(plugins)? {
let entry = entry?;
if !entry.file_type()?.is_dir() {
continue;
}
count += 1;
ensure!(count <= 64, "Too many plugin descriptors");
let descriptor = entry.path().join(".mcp.json");
if !descriptor.exists() {
continue;
}
let data: Value = serde_json::from_slice(&read_regular(&descriptor, 1024 * 1024)?)?;
keys.insert(selected_key(&data, &paths.runtime_root)?);
}
ensure!(
keys.len() <= 1,
"Ambiguous runtime selection; no cache was modified"
);
Ok(keys.into_iter().next())
}
fn prepare(paths: &BrowserPaths, key: &str, contract: &RuntimeContract) -> Result<()> {
ensure!(key_valid(key), "Invalid runtime key");
let runtime = paths.runtime_root.join(key);
let target = runtime.join(SERVICE);
let _runtime_guards = pin_parents(&target)?;
for (file, expected) in &contract.files {
ensure!(
sha(&read_regular(&runtime.join(file), 128 * 1024 * 1024)?) == *expected,
"Unsupported native runtime component: {file}"
);
}
let mut current = read_regular(&target, MAX_SERVICE)?;View on GitHub (pinned to b1ed92e5e4)