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

  1. Delete or fix the stale descriptor(s) so all remaining .mcp.json files select the same runtime key
  2. Remove the outdated runtime directory under the runtime root and its descriptor together, keeping only the current pair
  3. 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

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


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)