{"record":{"id":"c727a2712fa664df","repo":"tinyhumansai/openhuman","slug":"api-request-failed-message","errorCode":null,"errorMessage":"API request failed: {message}","messagePattern":"API request failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/api/rest.rs","lineNumber":311,"sourceCode":"/// than `{success,data}`; SDK transport must not expose that envelope detail to\n/// existing callers.\nfn parse_api_response_value(value: Value) -> Result<Value> {\n    let Some(object) = value.as_object() else {\n        return Ok(value);\n    };\n    if let Some(user) = object.get(\"user\").filter(|user| !user.is_null()) {\n        return Ok(user.clone());\n    }\n    let Some(success) = object.get(\"success\").and_then(Value::as_bool) else {\n        return Ok(value);\n    };\n    if !success {\n        let message = object\n            .get(\"message\")\n            .or_else(|| object.get(\"error\"))\n            .and_then(Value::as_str)\n            .unwrap_or(\"request unsuccessful\");\n        anyhow::bail!(\"API request failed: {message}\");\n    }\n    if let Some(data) = object.get(\"data\").filter(|data| !data.is_null()) {\n        return Ok(data.clone());\n    }\n    if let Some(user) = object.get(\"user\").filter(|user| !user.is_null()) {\n        return Ok(user.clone());\n    }\n    let mut unwrapped = object.clone();\n    unwrapped.remove(\"success\");\n    Ok(Value::Object(unwrapped))\n}\n\nfn user_id_from_object(obj: &serde_json::Map<String, Value>) -> Option<String> {\n    for key in [\"id\", \"_id\", \"userId\"] {\n        if let Some(s) = obj.get(key).and_then(|x| x.as_str()) {\n            let t = s.trim();\n            if !t.is_empty() {\n                return Some(t.to_string());","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/api/rest.rs#L293-L329","documentation":"authed_json unwraps the TinyHumans backend's { success, data, user } envelope; when the parsed JSON body has success=false it bails with 'API request failed: {message}', taking the body's message or error field ('request unsuccessful' when neither exists). It means the backend received and answered the request with a business-level failure - distinct from transport errors and from the separately-handled 401/404 statuses.","triggerScenarios":"Any SDK-backed authed_json call whose backend handler responds 2xx-wrapped (or 200-with) success=false: invalid or newly-required parameters, entitlement or plan restrictions, semantically rejected payloads, or account-level feature flags.","commonSituations":"A backend rollout tightened validation and the client still sends the old payload shape; a newly required field was missed; the account lacks an entitlement the route checks.","solutions":["Inspect the embedded {message} - it is the backend's own failure text and usually names the exact problem.","Verify the request payload against the current vendored SDK route definition (the SDK is the source of truth for routes and params).","Check for version skew between the app, the vendored SDK submodule, and the backend.","If the message smells like auth but the call got this far, remember real 401 session expiry is classified separately - this path is a body-level rejection."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"In Rust callers, match on the anyhow error: if the message starts with 'API request failed:', surface the remainder (the backend's message) to the user as a validation or entitlement problem; otherwise propagate. When using SDK-typed routes, prefer classify_sdk_error so Sentry and session-expiry behavior stay consistent.","preventionTips":["Validate request payloads client-side against the vendored SDK route definitions before sending.","Keep app, SDK submodule, and backend versions aligned to avoid envelope-contract drift.","Log method plus path alongside the error for correlation."],"tags":["backend-api","http","envelope","validation","sdk"],"backgroundTag":"backend-error-response","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}