{"record":{"id":"3e0256af5fcb8aae","repo":"headroomlabs-ai/headroom","slug":"recommendations-file-not-found-0","errorCode":null,"errorMessage":"recommendations file not found: {0}","messagePattern":"recommendations file not found: (.+?)","errorType":"exception","errorClass":"RecommendationsError","httpStatus":null,"severity":"error","filePath":"crates/headroom-core/src/transforms/recommendations.rs","lineNumber":252,"sourceCode":"\n/// Module-level convenience: look up a recommendation in the global\n/// store. PR-F3 will wire this into `dispatch_compressor`. PR-B5 only\n/// exposes the API surface.\npub fn get(\n    auth_mode: AuthMode,\n    model: &str,\n    structure_hash: &str,\n) -> Option<&'static Recommendation> {\n    load_default().lookup(auth_mode, model, structure_hash)\n}\n\n/// Errors surfaced by the loader. Marked non-exhaustive so we can add\n/// future variants without breaking callers.\n#[derive(Debug, thiserror::Error)]\n#[non_exhaustive]\npub enum RecommendationsError {\n    /// File doesn't exist on disk.\n    #[error(\"recommendations file not found: {0}\")]\n    Missing(PathBuf),\n    /// Filesystem error other than NotFound.\n    #[error(\"recommendations IO error at {path}: {source}\")]\n    Io {\n        path: PathBuf,\n        #[source]\n        source: std::io::Error,\n    },\n    /// TOML parse failure (typed wrapper for ergonomics).\n    #[error(\"recommendations TOML parse error: {0}\")]\n    Parse(#[from] toml::de::Error),\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn sample_toml() -> &'static str {","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/crates/headroom-core/src/transforms/recommendations.rs#L234-L270","documentation":"The non-object-JSON rejection in _read_json_body_with_bytes (helpers.py:2551), the shared reader behind the Anthropic, OpenAI, and Bedrock request paths. The body is valid JSON but its root is not an object (list/str/int/bool/null), and these APIs require an object.","triggerScenarios":"Sending an array-wrapped or scalar JSON body to any main proxied chat route (Anthropic /v1/messages, OpenAI-compatible /v1/chat/completions, Bedrock translation path).","commonSituations":"Batch-style clients, double-serialized strings, or fixture reuse from other APIs hitting the primary proxy paths.","solutions":["Send a top-level JSON object with the expected schema keys","Guard client-side: assert isinstance(json.loads(text), dict)","Remove wrapping middleware that envelopes payloads in arrays"],"exampleFix":"// before (js)\nfetch(url, {body: JSON.stringify([msg])})\n// after\nfetch(url, {body: JSON.stringify({model, messages: [msg]})})","handlingStrategy":"type-guard","validationCode":"assert isinstance(payload, dict), f\"request must be a JSON object, got {type(payload).__name__}\"","typeGuard":"def is_request_object(v: object) -> TypeGuard[dict]:\n    return isinstance(v, dict)","tryCatchPattern":"try:\n    result, raw = await _read_json_body_with_bytes(request)\nexcept ValueError as exc:\n    return JSONResponse({\"error\": str(exc)}, status_code=400)","preventionTips":["Don't reuse batch-API wrappers against single-request endpoints","Check for double json.dumps in client code"],"tags":["json","validation","request-body"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}