headroomlabs-ai/headroom · error · ConfigError
invalid pipeline config TOML: {0}
Error message
invalid pipeline config TOML: {0} What it means
The body parsed as JSON but the top-level value is not an object — e.g. a JSON array, string, or number (helpers.py:2519). The Anthropic/OpenAI-style request schema is a JSON object, so arrays like '[{...}]' or bare strings are rejected with the actual type name embedded in the message.
Source
Thrown at crates/headroom-core/src/transforms/pipeline/config.rs:221
pub struct ProseFieldConfig {
pub min_bytes: usize,
pub min_segments: usize,
pub target_ratio: f64,
}
/// Knobs for the [`crate::transforms::pipeline::offloads::DiffNoise`]
/// offload. Lockfile suffixes are matched against the new-file path
/// at the end of each `diff --git` header.
#[derive(Debug, Clone, Deserialize)]
pub struct DiffNoiseConfig {
pub min_lines: usize,
pub lockfile_suffixes: Vec<String>,
pub drop_whitespace_only_hunks: bool,
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("invalid pipeline config TOML: {0}")]
Parse(#[from] toml::de::Error),
#[error("could not read pipeline config file: {0}")]
Io(std::io::Error),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_default_str_does_not_panic() {
// Embedded TOML must always deserialize cleanly.
let _ = PipelineConfig::from_default_str();
}
#[test]
fn defaults_match_documented_thresholds() {
let cfg = PipelineConfig::default();View on GitHub (pinned to 322425c43b)
Solutions
- Send a single JSON object at the top level: {"model": ..., "messages": [...]}
- Check for double serialization: if your payload is a str after dumps, you serialized twice
- Validate the body client-side: isinstance(payload, dict) before sending
Example fix
# before
requests.post(url, json=[{"model": "claude", "messages": msgs}])
# after
requests.post(url, json={"model": "claude", "messages": msgs}) Defensive patterns
Strategy: type-guard
Validate before calling
payload = json.loads(text)
if not isinstance(payload, dict):
raise TypeError(f"expected a JSON object, got {type(payload).__name__}") Type guard
def is_request_object(value: object) -> bool:
return isinstance(value, dict) Try / catch
try:
payload = await _read_json_body(request)
except ValueError as exc:
return JSONResponse({"error": str(exc)}, status_code=400) Prevention
- Use request libraries' json= parameter so serialization happens once
- Assert dict payloads in client-side test fixtures
When it happens
Trigger: POSTing '[{"model": ...}]' (array-wrapped request) to a proxied route; sending a JSON string '"hello"' or a bare number; a client that wraps payloads for batching APIs and reuses the same code against headroom.
Common situations: Porting code from batch APIs that accept arrays; accidental double-serialization (json.dumps applied twice yields a string); test fixtures copied from other APIs.
Related errors
- recommendations file not found: {0}
- items_json must be JSON: {e}
- doc_json must be JSON: {e}
- ccr sqlite backend init failed: {0}
- ccr redis backend init failed: {0}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/6438a40322cb98b3.
Report an issue: GitHub.