BigPizzaV3/CodexPlusPlus · error
的模型 值必须是字符串
Error message
{field_name} 的模型 {key} 值必须是字符串 What it means
When iterating the parsed JSON object, parse_model_string_map requires every value to be a JSON string (value.as_str). If any entry's value is a number, boolean, object or array, it throws "{field_name} 的模型 {key} 值必须是字符串" naming the offending model key. This keeps map fields uniformly string-typed.
Solutions
- Quote the value: change {"model": 1000000} to {"model": "1000000"}.
- Convert all numeric/boolean values in the field to strings before saving the profile.
- Sanitize with code: after parsing, map every value through to_string() and re-serialize.
- Prefer the `model[1M]` list syntax which avoids the JSON map entirely.
Example fix
// before
model_windows = "{\"deepseek-v4-pro\": 1000000}"
// after
model_windows = "{\"deepseek-v4-pro\": \"1000000\"}" Defensive patterns
Strategy: type-guard
Validate before calling
fn all_values_are_strings(json: &str) -> bool {
serde_json::from_str::<serde_json::Value>(json).ok()
.and_then(|v| v.as_object().cloned())
.map(|o| o.values().all(|v| v.is_string()))
.unwrap_or(false)
} Type guard
fn is_string_entry((k, v): (&String, &serde_json::Value)) -> bool {
v.is_string() || { eprintln!("{k} value must be a string"); false }
} Try / catch
match normalize_relay_profile_for_storage(profile) {
Err(e) if e.to_string().contains("值必须是字符串") => {
// re-serialize offending numeric values with to_string() and retry
}
other => other?,
} Prevention
- Quote all values in map fields: "1000000" not 1000000
- Run map values through v.to_string() when generating JSON programmatically
- Add string-only schema validation in the settings UI
When it happens
Trigger: model_windows written as {"deepseek-v4-pro": 1000000} (number) or {"deepseek-v4-pro": true} instead of a quoted string value.
Common situations: Users entering window sizes as bare integers (natural in JSON) without quotes; JSON produced by other tooling that serializes numeric windows.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/7f43e6ca45dacc8b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/relay_config.rs:2112
fn parse_model_string_map(
value: &str,
field_name: &str,
) -> anyhow::Result<HashMap<String, String>> {
if value.trim().is_empty() {
return Ok(HashMap::new());
}
let parsed: Value = serde_json::from_str(value)
.map_err(|error| anyhow::anyhow!("{field_name} JSON 解析失败:{error}"))?;
let object = parsed
.as_object()
.ok_or_else(|| anyhow::anyhow!("{field_name} 必须是 JSON 对象"))?;
object
.iter()
.map(|(key, value)| {
let value = value
.as_str()
.ok_or_else(|| anyhow::anyhow!("{field_name} 的模型 {key} 值必须是字符串"))?;
Ok((key.clone(), value.to_string()))
})
.collect()
}
fn validate_model_windows(model_windows: &HashMap<String, String>) -> anyhow::Result<()> {
for (slug, value) in model_windows {
if crate::model_suffix::parse_window_token(value).is_none() {
anyhow::bail!("model_windows 的模型 {slug} 窗口值无效:{value}");
}
}
Ok(())
}
fn validate_model_auto_compact(model_auto_compact: &HashMap<String, String>) -> anyhow::Result<()> {
for (slug, value) in model_auto_compact {
if crate::model_suffix::parse_compact_percent(value).is_none() {
anyhow::bail!("model_auto_compact 的模型 {slug} 百分比无效:{value}");View on GitHub (pinned to b1ed92e5e4)