farion1231/cc-switch · error

volcengine handled via AK/SK branch above

Error message

volcengine handled via AK/SK branch above

What it means

This is a Rust `unreachable!()` panic used as a defensive guard in `get_coding_plan_quota` (src-tauri/src/services/coding_plan.rs:1466). Volcengine is supposed to be routed to a dedicated AK/SK-signing branch that returns early (lines 1438-1447), because it authenticates with Volcengine control-plane AccessKey ID + Secret instead of the data-plane Bearer API key used by all other providers. If control flow ever reaches the `CodingPlanProvider::Volcengine` match arm at the bottom, it means the early AK/SK branch was skipped or removed — an internal invariant violation, not a user-facing condition. The library panics deliberately to fail loudly during development rather than silently query Volcengine with the wrong auth scheme.

Source

Thrown at src-tauri/src/services/coding_plan.rs:1466

    // 其余供应商:数据面 Bearer api_key。
    // 与 balance::get_balance 一致:给出明确错误,避免 footer 显示无信息的失败
    if api_key.trim().is_empty() {
        return Ok(coding_plan_not_found("API key is empty"));
    }

    match provider {
        CodingPlanProvider::Kimi => query_kimi(api_key).await,
        CodingPlanProvider::ZhipuCn | CodingPlanProvider::ZhipuEn => {
            query_zhipu(base_url, api_key).await
        }
        CodingPlanProvider::MiniMaxCn => query_minimax(api_key, true).await,
        CodingPlanProvider::MiniMaxEn => query_minimax(api_key, false).await,
        CodingPlanProvider::ZenMux => query_zenmux(base_url, api_key).await,
        CodingPlanProvider::OpencodeGo => query_opencode_go(api_key).await,
        // 火山已在上面的 AK/SK 分支提前返回,此处不可达。
        CodingPlanProvider::Volcengine => {
            unreachable!("volcengine handled via AK/SK branch above")
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{
        detect_provider, parse_afp_tiers, parse_coding_plan_tiers, parse_minimax_tiers,
        parse_opencode_go_tiers, parse_zhipu_token_tiers, query_zhipu_team_at,
        volcengine_canonical_query, volcengine_is_auth_error_code, volcengine_region,
        volcengine_response_error, volcengine_sign, zhipu_quota_base, CodingPlanProvider,
        TIER_FIVE_HOUR, TIER_MONTHLY, TIER_WEEKLY_LIMIT,
    };
    use serde_json::json;

    #[test]
    fn opencode_go_detects_both_base_variants_but_not_zen() {
        // claude/claude-desktop 预设 base 是 /zen/go,codex/opencode/pi 是

View on GitHub (pinned to 3217f72596)

Solutions

  1. Inspect the code between `detect_provider` and the final `match`: confirm the `if let CodingPlanProvider::Volcengine = provider` block (lines 1438-1447) is still present, still returns early, and was not bypassed by an earlier `return`/branch.
  2. Check whether a recent commit moved or restructured the AK/SK early-return (e.g. converted the `if let` into a `match` on provider placed after the final match); restore the early return before the api_key check.
  3. Update the exhaustive match if a new provider variant was added and Volcengine handling was accidentally relocated; keep the `unreachable!()` only if the AK/SK branch provably returns for every Volcengine path.
  4. Run the existing test suite (the `#[cfg(test)]` module exercises this routing) and add a test asserting a Volcengine base_url with AK/SK credentials never reaches the panic arm.
  5. If Volcengine legitimately needs data-plane handling in the future, replace the `unreachable!()` arm with a real `query_volcengine`-style call instead of keeping a stale guard.

Example fix

// before (regression: AK/SK early-return removed)
let provider = match detect_provider(base_url) { ... };
if api_key.trim().is_empty() { ... }
match provider {
    CodingPlanProvider::Volcengine => unreachable!("volcengine handled via AK/SK branch above"),
    _ => ...
}
// after (restore the AK/SK branch before the api_key check)
let provider = match detect_provider(base_url) { ... };
if let CodingPlanProvider::Volcengine = provider {
    let (ak, sk) = (access_key_id.unwrap_or("").trim(), secret_access_key.unwrap_or("").trim());
    if ak.is_empty() || sk.is_empty() {
        return Ok(coding_plan_not_found("Volcengine usage query needs the account AccessKey ID + Secret (not the inference API key)"));
    }
    return query_volcengine(base_url, ak, sk).await;
}
if api_key.trim().is_empty() { ... }
match provider { /* Volcengine arm stays unreachable */ }
Defensive patterns

Strategy: validation

Validate before calling

// Caller-side check before invoking the quota API: ensure Volcengine
// requests supply AK/SK credentials so the early branch handles them.
fn validate_quota_request(base_url: &str, ak: Option<&str>, sk: Option<&str>) -> Result<(), String> {
    if is_volcengine_base_url(base_url) {
        match (ak, sk) {
            (Some(ak), Some(sk)) if !ak.trim().is_empty() && !sk.trim().is_empty() => Ok(()),
            _ => Err("Volcengine requires AccessKey ID + Secret (not the inference API key)".into()),
        }
    } else {
        Ok(())
    }
}

Type guard

fn is_volcengine(provider: &CodingPlanProvider) -> bool {
    matches!(provider, CodingPlanProvider::Volcengine)
}

Try / catch

// Rust has no catch for panics in the same task; isolate with catch_unwind
// and surface a deterministic failure instead of crashing the app:
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(||
    futures::executor::block_on(get_coding_plan_quota(base_url, api_key, ak, sk, provider, org, proj))
));
match result {
    Ok(Ok(quota)) => render_quota(quota),
    Ok(Err(transient)) => retry_with_backoff(transient),
    Err(_panic) => render_error("Internal routing error: provider handling inconsistent"),
}

Prevention

When it happens

Trigger: The only way to trigger it is a code regression: `detect_provider(base_url)` returns `CodingPlanProvider::Volcengine` but the preceding `if let CodingPlanProvider::Volcengine = provider { ... }` early-return block no longer executes or was deleted — e.g. someone adds a new provider branch above that mistakenly swallows/redirects the Volcengine case, refactors the AK/SK branch into a `match` that falls through, or edits the match arms without updating the unreachable guard. It cannot be triggered by any API input (base_url, api_key, AK/SK values) in the current code.

Common situations: Seen during development after refactoring `get_coding_plan_quota`'s provider routing, after adding new `CodingPlanProvider` enum variants, or when a contributor merges a change to the Volcengine early-return block without re-running tests. End users never hit it in a released build.

Related errors


AI-assisted analysis of farion1231/cc-switch@3217f72596 (2026-08-29). Data as JSON: /api/errors/6d1b3edf169e79fa. Report an issue: GitHub.