Hmbown/CodeWhale · error
model must be nonempty and contain no control characters
Error message
model must be nonempty and contain no control characters
What it means
set_provider_model_document writes a provider's model into the TOML document, but first validates the model string: it must be non-empty after trimming and contain no control characters, since control characters would corrupt the config file or downstream requests. This ensure! rejects empty, whitespace-only, or control-character-bearing model names.
Solutions
- Trim and validate the model string before calling any persistence API; reject empty/control chars at the input boundary
- Fix the upstream source of the model name (env var, config field, model list) so it supplies a real model id
- Sanitize pasted/CLI model identifiers by stripping whitespace and rejecting control characters
Example fix
// before persist_provider_model_key(provider, identity, "\n")?; // after let model = raw_model.trim(); anyhow::ensure!(!model.is_empty() && !model.chars().any(char::is_control)); persist_provider_model_key(provider, identity, model)?;
Defensive patterns
Strategy: validation
Validate before calling
fn valid_model_name(m: &str) -> bool {
let t = m.trim();
!t.is_empty() && !m.chars().any(char::is_control)
}
// gate every persistence call on valid_model_name(model) Try / catch
match persist_provider_model_key(provider, identity, model) {
Err(e) if e.to_string().contains("model must be nonempty") => {
reprompt_for_model();
}
other => other?,
} Prevention
- Trim model input at the CLI/UI boundary and reject empty values immediately
- Sanitize pasted model ids (strip control characters)
- Never persist a model field sourced from an unset env var without a default
When it happens
Trigger: Calling any of the callers (persist_provider_selection, persist_provider_model_key, migrate_legacy_route_preferences, reconcile_root_model_aliases) with model == "", a whitespace string, or a string containing \n, \t, \r or other control chars.
Common situations: A model field read from a broken input source (empty env var, blank UI field); pasting a model id with embedded newline; upstream listing code returning empty strings for missing models.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- agent profile provider cannot be empty
- agent profile provider must be a simple provider id
- api_key cannot be empty string
- approval_policy ' ' is not allowed by requirements ( )
- budget document_kind must be
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/5f0793511936f886.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/config_persistence.rs:163
}
set_provider_model_document(
doc,
identity.provider,
identity.persisted_id().unwrap_or(&identity.key),
model,
)?;
}
}
set_document_value(doc, &["route_preferences_version"], 1_i64)
}
pub(crate) fn set_provider_model_document(
doc: &mut toml_edit::DocumentMut,
provider: ApiProvider,
provider_identity: &str,
model: &str,
) -> anyhow::Result<()> {
anyhow::ensure!(
!model.trim().is_empty() && !model.chars().any(char::is_control),
"model must be nonempty and contain no control characters"
);
let config: crate::config::Config = toml::from_str(&doc.to_string()).map_err(|_| {
anyhow::anyhow!("Could not parse destination route identity; contents omitted")
})?;
let identity = config
.resolve_provider_pin_identity(provider_identity)
.map_err(anyhow::Error::msg)?;
anyhow::ensure!(
identity.provider == provider,
"The destination config has a different provider identity"
);
let provider_key = if provider == ApiProvider::Custom {
if identity.persisted_id().is_none() {
return set_document_value(doc, &["default_text_model"], model);
}
identity.keyView on GitHub (pinned to 73e0f67d83)