{"record":{"id":"744de9b46714a844","repo":"BigPizzaV3/CodexPlusPlus","slug":"model-catalog-json","errorCode":null,"errorMessage":"当前配置使用外部 model_catalog_json，无法同时应用每模型窗口、自动压缩或元数据","messagePattern":"当前配置使用外部 model_catalog_json，无法同时应用每模型窗口、自动压缩或元数据","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/relay_config.rs","lineNumber":2007,"sourceCode":"    let fallback = parse_optional_positive_u64(&profile.context_window, \"上下文大小\")?;\n    // 用户已手写 model_catalog_json 指针时保留，不覆盖（保 preserves_user_model_catalog_json 测试）。\n    // Codex++ 管理的 catalog 必须随当前 profile 切换；否则前一个供应商的模型列表会残留。\n    // cc-switch 的固定文件名属于已知的其他管理器投影，不视为用户手写 catalog；\n    // 切换到 Codex++ profile 时应接管，否则旧 catalog 会继续覆盖本 profile 的模型元数据。\n    if let Some(existing) = root_key_string(&config_text, \"model_catalog_json\") {\n        if existing != catalog_relative {\n            if is_codex_plus_managed_model_catalog(home, &existing)\n                || is_cc_switch_model_catalog(&existing)\n            {\n                config_text = remove_root_key(&config_text, \"model_catalog_json\");\n            } else if model_catalog_pointer_has_unexpanded_variable(&existing) {\n                // `%userprofile%\\.codex\\codex-models.json` 这类指针 codex 不展开变量，\n                // 在任何机器上都读不到，留着会让 codex 拒绝加载整份 config.toml\n                // （#2123）。去掉它不会比现在更差——这份 catalog 反正从未生效过。\n                config_text = remove_root_key(&config_text, \"model_catalog_json\");\n            } else {\n                if has_per_model_overrides {\n                    anyhow::bail!(\n                        \"当前配置使用外部 model_catalog_json，无法同时应用每模型窗口、自动压缩或元数据\"\n                    );\n                }\n                if official_deepseek_responses {\n                    return Ok(config_text.to_string());\n                }\n                if custom_responses\n                    && copy_standard_responses_catalog(\n                        home,\n                        &existing,\n                        &catalog_relative,\n                        &entries,\n                        fallback,\n                    )?\n                {\n                    let mut doc = parse_toml_document(&config_text)?;\n                    doc[\"model_catalog_json\"] = toml_edit::value(catalog_relative);\n                    return Ok(normalize_optional_toml(doc));","sourceCodeStart":1989,"sourceCodeEnd":2025,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/relay_config.rs#L1989-L2025","documentation":"When the managed config.toml already points at an external model_catalog_json file, the library cannot generate a merged catalog that also carries per-model window/auto-compact/metadata overrides; mixing the two is unsafe, so it bails when has_per_model_overrides is true. Without overrides it proceeds by removing or ignoring the pointer.","triggerScenarios":"Calling the apply pipeline (apply_relay_profile_to_home_with_switch_rules → apply_context_limits_to_config) with per-model overrides while config.toml's model_catalog_json key references an external catalog file, and the catalog is not treated as official-deepseek-responses.","commonSituations":"User previously enabled an external catalog (e.g. codex-models.json pointer) and now tries to apply per-model windows via model_list[1M] syntax; configs migrated from other tools retain a model_catalog_json pointer.","solutions":["Remove the model_catalog_json key from config.toml so the library can generate its own catalog","Or drop the per-model window/auto-compact/metadata overrides for this apply","Convert the external catalog's entries into in-config model_windows values, then re-apply"],"exampleFix":"// before (config.toml)\nmodel_catalog_json = \"%userprofile%\\\\.codex\\\\codex-models.json\"\n// after (config.toml)\n# key removed; let CodexPlusPlus generate the catalog\n","handlingStrategy":"validation","validationCode":"let doc: toml_edit::DocumentMut = config_text.parse()?;\nlet has_external = doc.get(\"model_catalog_json\").is_some();\nif has_external && has_per_model_overrides {\n    return Err(anyhow::anyhow!(\"移除 model_catalog_json 或取消每模型覆盖\"));\n}","typeGuard":null,"tryCatchPattern":"match apply_relay_profile_to_home_with_switch_rules(...) {\n    Err(e) if e.to_string().contains(\"外部 model_catalog_json\") => confirm_remove_catalog_pointer_then_retry(),\n    other => other?,\n}","preventionTips":["Strip model_catalog_json pointers when enabling per-model windows","Detect external catalogs during profile apply and warn first","Keep catalog generation owned by one mechanism only"],"tags":["config","conflict","catalog"],"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"}