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
- 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.
- 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.
- 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.
- 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.
- 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
- Never remove or reorder the AK/SK early-return block for Volcengine without updating the final match arm.
- Add a unit test per CodingPlanProvider variant asserting get_coding_plan_quota routes without panicking.
- When adding a new enum variant, fix the exhaustive match immediately rather than using a catch-all arm that hides regressions.
- Run `cargo test` on the services module in CI so any path reaching the `unreachable!()` arm fails the build.
- Keep provider routing (detect + branch) in one function so the invariant 'Volcengine returns early' is locally visible.
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.