sigoden/aichat · error · anyhow::Error
Invalid request json
Error message
Invalid request json, {err} What it means
The /search-rag handler reads the request body and deserializes it as JSON; malformed JSON fails with this error (a second, distinct error covers valid JSON with wrong fields). The raw serde error is interpolated for diagnosis.
Solutions
- Send a valid JSON body with Content-Type: application/json
- Validate the payload with a JSON linter before sending
- Ensure the body isn't empty or truncated in transit
Example fix
// before
curl -X POST localhost:8000/search-rag -d name=docs
// after
curl -X POST localhost:8000/search-rag -H 'Content-Type: application/json' -d '{"name":"docs","input":"query"}' Defensive patterns
Strategy: validation
Validate before calling
fn valid_search_body(s: &str) -> bool {
serde_json::from_str::<serde_json::Value>(s)
.ok()
.map(|v| v.get("name").is_some() && v.get("input").is_some())
.unwrap_or(false)
} Type guard
fn as_search_body(b: &[u8]) -> Option<(String, String)> {
let v: serde_json::Value = serde_json::from_slice(b).ok()?;
Some((v.get("name")?.as_str()?.into(), v.get("input")?.as_str()?.into()))
} Try / catch
let res = client.post(url).json(&json!({"name": rag, "input": q})).send().await?;
if res.status().is_client_error() {
let msg = res.text().await?;
eprintln!("Bad request: {msg}");
} Prevention
- Always send Content-Type: application/json with a JSON body
- Validate payloads client-side before POSTing
- Never send empty bodies to /search-rag
When it happens
Trigger: POSTing to search_rag with a body that is not valid JSON: empty body, HTML/plain text, truncated JSON, or wrong Content-Type payload.
Common situations: Forgetting to send a body; curl without proper quoting; clients sending form-encoded data; proxies truncating large bodies.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- The model does not support network images
- The model does not support network images
- Invalid response data
- The call ' ' has invalid arguments
- {err}
AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09).
Data as JSON: /api/errors/c443bbf0e662eb5a.
Report an issue: GitHub.
Appendix: source
Thrown at src/serve.rs:239
let data = json!({ "data": self.roles });
let res = Response::builder()
.header("Content-Type", "application/json; charset=utf-8")
.body(Full::new(Bytes::from(data.to_string())).boxed())?;
Ok(res)
}
fn list_rags(&self) -> Result<AppResponse> {
let data = json!({ "data": self.rags });
let res = Response::builder()
.header("Content-Type", "application/json; charset=utf-8")
.body(Full::new(Bytes::from(data.to_string())).boxed())?;
Ok(res)
}
async fn search_rag(&self, req: hyper::Request<Incoming>) -> Result<AppResponse> {
let req_body = req.collect().await?.to_bytes();
let req_body: Value = serde_json::from_slice(&req_body)
.map_err(|err| anyhow!("Invalid request json, {err}"))?;
debug!("search rag request: {req_body}");
let SearchRagReqBody { name, input } = serde_json::from_value(req_body)
.map_err(|err| anyhow!("Invalid request body, {err}"))?;
let config = Arc::new(RwLock::new(self.config.clone()));
let abort_signal = create_abort_signal();
let rag_path = config.read().rag_file(&name);
let rag = Rag::load(&config, &name, &rag_path)?;
let rag_result = Config::search_rag(&config, &rag, &input, abort_signal).await?;
let data = json!({ "data": rag_result });
let res = Response::builder()
.header("Content-Type", "application/json; charset=utf-8")
.body(Full::new(Bytes::from(data.to_string())).boxed())?;View on GitHub (pinned to 82976d349a)