BigPizzaV3/CodexPlusPlus · error

Grok 模型 不能同时替换并移除 API Key

Error message

Grok 模型 {alias} 不能同时替换并移除 API Key

What it means

A model entry may either replace the API key (api_key_update non-empty) or mark it for removal (remove_api_key = true), but not both. validate_request rejects the combination because the two operations are contradictory — there is no defined outcome for 'set this key and remove it'.

Solutions

  1. Set remove_api_key = false and keep api_key_update with the new key to rotate
  2. Clear api_key_update (empty string) and keep remove_api_key = true to delete the key
  3. Reset the form state so only one of the two fields is ever populated

Example fix

// before
remove_api_key: true, api_key_update: "sk-new"
// after
remove_api_key: false, api_key_update: "sk-new"
Defensive patterns

Strategy: validation

Validate before calling

assert!(!(req.remove_api_key && !req.api_key_update.is_empty()), "cannot replace and remove the key at once");

Prevention

When it happens

Trigger: save_grok_config_at called with input.remove_api_key == true AND input.api_key_update non-empty, typically when a UI checkbox is left checked while a new key is also typed in, or when merging request objects.

Common situations: Editing a model to rotate the key while the 'remove key' toggle from a previous edit is still on; JSON merge patches layering both fields; scripted updates that always set both fields.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/da87f5129debaa88. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/grok_config.rs:305

            bail!("Grok 模型来源别名重复:{source}");
        }
        if !matches!(
            input.api_backend.trim(),
            "responses" | "chat_completions" | "messages"
        ) {
            bail!("Grok 模型 {alias} 的 API 协议无效");
        }
        if input.context_window == Some(0) {
            bail!("Grok 模型 {alias} 的上下文窗口必须大于 0");
        }
        if input
            .context_window
            .is_some_and(|value| value > i64::MAX as u64)
        {
            bail!("Grok 模型 {alias} 的上下文窗口过大");
        }
        if input.remove_api_key && !input.api_key_update.is_empty() {
            bail!("Grok 模型 {alias} 不能同时替换并移除 API Key");
        }
    }
    Ok(())
}

fn table_string(doc: &DocumentMut, table: &str, key: &str) -> String {
    doc.get(table)
        .and_then(Item::as_table_like)
        .and_then(|values| values.get(key))
        .and_then(Item::as_str)
        .unwrap_or_default()
        .to_string()
}

fn item_string<T: TableLike + ?Sized>(table: &T, key: &str) -> String {
    table
        .get(key)
        .and_then(Item::as_str)

View on GitHub (pinned to b1ed92e5e4)