BigPizzaV3/CodexPlusPlus · error
倍率接口返回了无效用户倍率
Error message
倍率接口返回了无效用户倍率
What it means
The same validator then checks the optional user_rate_multiplier with the identical finite-and-nonnegative rule. It fires only when the field is present (Some) but carries an invalid value, again guarding rate computations.
Solutions
- 在 sub2api 后台修正该用户/密钥的自定义倍率为非负有限值
- 若不需要用户级倍率,删除该字段让 Option 为 None
- 升级上游修复非法值的序列化问题
Example fix
// before
if let Some(value) = response.user_rate_multiplier {
if !value.is_finite() || value < 0.0 {
anyhow::bail!("倍率接口返回了无效用户倍率");
}
}
// after
if let Some(value) = response.user_rate_multiplier {
if !value.is_finite() || value < 0.0 {
tracing::warn!("忽略无效用户倍率: {value},回退到 effective_rate_multiplier");
}
} Defensive patterns
Strategy: try-catch
Validate before calling
fn user_multiplier_sane(body: &serde_json::Value) -> bool {
match body.get("user_rate_multiplier") {
None | Some(serde_json::Value::Null) => true,
Some(v) => v.as_f64().map(|x| x.is_finite() && x >= 0.0).unwrap_or(false),
}
} Try / catch
match fetch_sub2api_billing_info(&profile).await {
Err(e) if e.to_string().contains("无效用户倍率") => {
eprintln!("用户自定义倍率非法:{e},已跳过,请修正 sub2api 用户倍率配置");
}
other => other?,
} Prevention
- 后台设置用户倍率时只输入非负数字
- 不需要用户级倍率时留空而不是填 0 或负数
- 定期审计用户级倍率配置,防止误输入
When it happens
Trigger: 上游响应中 user_rate_multiplier 存在但值为 NaN、无穷或负数。
Common situations: 用户在 sub2api 后台手动输入了非法的用户倍率;上游对 null/缺失值的序列化 bug;管理员误配负数倍率。
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/03afa8bb174e8990.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/sub2api.rs:121
fn validate_sub2api_billing_response(response: &Sub2ApiBillingResponse) -> anyhow::Result<()> {
if response.object != "sub2api.key_billing"
|| response.schema_version != 1
|| response.billing_scope != "token"
{
anyhow::bail!("倍率接口返回结构不是 sub2api.key_billing");
}
for value in [
response.group_rate_multiplier,
response.resolved_rate_multiplier,
response.effective_rate_multiplier,
] {
if !value.is_finite() || value < 0.0 {
anyhow::bail!("倍率接口返回了无效倍率");
}
}
if let Some(value) = response.user_rate_multiplier {
if !value.is_finite() || value < 0.0 {
anyhow::bail!("倍率接口返回了无效用户倍率");
}
}
if response.observed_at.trim().is_empty() {
anyhow::bail!("倍率接口缺少观测时间");
}
Ok(())
}
fn sub2api_error_message(body: &str) -> Option<String> {
let payload: Value = serde_json::from_str(body).ok()?;
for path in [&["error", "message"][..], &["message"][..], &["error"][..]] {
let mut current = &payload;
for key in path {
current = current.get(*key)?;
}
if let Some(message) = current
.as_str()
.map(str::trim)View on GitHub (pinned to b1ed92e5e4)