{"record":{"id":"57c4821f0eb7268b","repo":"BigPizzaV3/CodexPlusPlus","slug":"ambiguous-runtime-selection-no-cache-was-modified","errorCode":null,"errorMessage":"Ambiguous runtime selection; no cache was modified","messagePattern":"Ambiguous runtime selection; no cache was modified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":360,"sourceCode":"        return Ok(None);\n    }\n    let mut keys = BTreeSet::new();\n    let mut count = 0;\n    for entry in fs::read_dir(plugins)? {\n        let entry = entry?;\n        if !entry.file_type()?.is_dir() {\n            continue;\n        }\n        count += 1;\n        ensure!(count <= 64, \"Too many plugin descriptors\");\n        let descriptor = entry.path().join(\".mcp.json\");\n        if !descriptor.exists() {\n            continue;\n        }\n        let data: Value = serde_json::from_slice(&read_regular(&descriptor, 1024 * 1024)?)?;\n        keys.insert(selected_key(&data, &paths.runtime_root)?);\n    }\n    ensure!(\n        keys.len() <= 1,\n        \"Ambiguous runtime selection; no cache was modified\"\n    );\n    Ok(keys.into_iter().next())\n}\n\nfn prepare(paths: &BrowserPaths, key: &str, contract: &RuntimeContract) -> Result<()> {\n    ensure!(key_valid(key), \"Invalid runtime key\");\n    let runtime = paths.runtime_root.join(key);\n    let target = runtime.join(SERVICE);\n    let _runtime_guards = pin_parents(&target)?;\n    for (file, expected) in &contract.files {\n        ensure!(\n            sha(&read_regular(&runtime.join(file), 128 * 1024 * 1024)?) == *expected,\n            \"Unsupported native runtime component: {file}\"\n        );\n    }\n    let mut current = read_regular(&target, MAX_SERVICE)?;","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L342-L378","documentation":"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\").","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"let mut keys = BTreeSet::new();\nfor dir in descriptor_dirs(&plugins) {\n    if let Ok(k) = selected_key(&read_descriptor(&dir)?, &runtime_root) { keys.insert(k); }\n}\nif keys.len() > 1 { eprintln!(\"descriptors select multiple runtimes: {keys:?}; remove stale ones\"); }","typeGuard":null,"tryCatchPattern":"match discover(&paths) {\n    Err(e) if e.to_string().contains(\"Ambiguous runtime selection\") => {\n        keep_only_newest_descriptor_dir(&plugins_cache)?; // remove stale version dirs, then retry\n        discover(&paths)\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["config","native-browser","ambiguity","plugin-cache"],"backgroundTag":"conflicting-config-options","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"}