tonhowtf/omniget · error
describe
Error message
describe: {} What it means
design_speak POSTs the natural-language description to {base}/design/describe and calls error_for_status(); any non-success response is wrapped as 'describe: {}'. It means the server rejected the voice-design description request that produces the synthesis instruct parameters.
Solutions
- Check the wrapped status in the error: 401/403 → credentials; 400/422 → description content.
- Ensure opts.description is non-empty and within the server's length limits before calling.
- Verify API key and base URL configuration.
- Confirm the VoiceStudio version still exposes /design/describe (endpoint may have changed).
- Retry with backoff on 429/5xx.
Example fix
// before
let j: serde_json::Value = c
.post(format!("{}/design/describe", b))
.json(&serde_json::json!({ "description": opts.description }))
.send()
.await?
.error_for_status()
.map_err(|e| anyhow!("describe: {}", e))?;
// after
anyhow::ensure!(!opts.description.trim().is_empty(), "describe: descricao vazia");
let resp = c.post(format!("{}/design/describe", b))
.json(&serde_json::json!({ "description": opts.description }))
.send().await?;
let j: serde_json::Value = resp.error_for_status()
.map_err(|e| anyhow!("describe: {}", e))?
.json().await?; Defensive patterns
Strategy: validation
Validate before calling
let desc = opts.description.trim();
if desc.is_empty() {
return Err("description must not be empty".into());
}
if desc.len() > 2000 {
return Err("description too long".into());
} Try / catch
match design_result {
Err(e) if e.to_string().contains("describe:") => {
let s = e.to_string();
if s.contains("401") || s.contains("403") { /* refresh API key */ }
else if s.contains("404") { /* endpoint changed: check VoiceStudio version */ }
else if s.contains("429") || s.contains("50") { /* backoff and retry */ }
else { /* surface to user */ }
}
other => other?,
} Prevention
- Require a non-empty, bounded-length description in the UI before submission.
- Verify API credentials before design operations.
- Pin/verify the VoiceStudio server version exposing /design/describe.
- Apply backoff on rate-limited or 5xx describe responses.
When it happens
Trigger: POST /design/describe returns 4xx/5xx: empty or overly long description text, invalid auth, unknown design endpoint, or a server error while interpreting the description.
Common situations: User submitted a blank description (opts.description empty), API token missing/expired, VoiceStudio backend updated the /design route, or rate limiting on the describe endpoint.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/e4fcc7f7349e27fd.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/tools/voicestudio.rs:401
pub unmatched: Vec<String>,
pub profile_id: Option<String>,
}
/// Descrição em texto → atributos → voz nova falando o texto.
pub async fn design_speak(
opts: DesignOptions,
progress: super::ProgressFn,
) -> anyhow::Result<DesignResult> {
let b = base(&opts.base_url);
let c = client(900)?;
super::report(&progress, "voicestudio", "describe", 0, None, None);
let j: serde_json::Value = c
.post(format!("{}/design/describe", b))
.json(&serde_json::json!({ "description": opts.description }))
.send()
.await?
.error_for_status()
.map_err(|e| anyhow!("describe: {}", e))?
.json()
.await?;
let instruct = j
.get("instruct")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let matched: Vec<String> = j
.get("matched")
.and_then(|v| v.as_array())
.map(|a| {
a.iter()
.filter_map(|m| m.get("phrase").and_then(|p| p.as_str()).map(String::from))
.collect()
})
.unwrap_or_default();
let unmatched: Vec<String> = j
.get("unmatched")View on GitHub (pinned to 8600b91f42)