{"record":{"id":"ad986534f5267f75","repo":"tinyhumansai/openhuman","slug":"no-announcement-available-404-on-announcements-l","errorCode":null,"errorMessage":"no announcement available (404 on /announcements/latest)","messagePattern":"no announcement available \\(404 on /announcements/latest\\)","errorType":"http","errorClass":"BackendApiError::AnnouncementNotFound","httpStatus":404,"severity":"error","filePath":"src/api/rest.rs","lineNumber":780,"sourceCode":"                        url.path(),\n                    );\n                }\n\n                // 404 on `/announcements/latest` means \"no announcement\" for\n                // this best-effort, cosmetic feature — not a code bug. Surface\n                // a typed `BackendApiError::AnnouncementNotFound` so the caller\n                // (`announcements::ops::get_latest_announcement`) can degrade to\n                // `null` instead of propagating an error, without funneling the\n                // 404 into `report_error`. Targets `TAURI-RUST-HW0` / `TAURI-RUST-KHX`.\n                if method == Method::GET && is_announcements_latest_path(url.path()) {\n                    tracing::info!(\n                        domain = \"backend_api\",\n                        operation = \"authed_json\",\n                        \"[backend_api] announcement-not-found 404 on {} {} — surfacing typed error\",\n                        method.as_str(),\n                        url.path(),\n                    );\n                    return Err(anyhow::Error::new(BackendApiError::AnnouncementNotFound));\n                }\n            }\n\n            // These are transient infrastructure errors (proxy/CDN/backend\n            // temporarily unavailable). They are not code bugs and callers already\n            // implement retry/disable logic, so skip Sentry to avoid noise.\n            let is_transient_infra =\n                crate::core::observability::is_transient_http_status_code(status_code);\n            let is_budget_exhausted = status_code == 400\n                && crate::openhuman::inference::provider::is_budget_exhausted_message(&text);\n            if is_budget_exhausted {\n                tracing::info!(\n                    method = method.as_str(),\n                    path = url.path(),\n                    status = status_code,\n                    failure = \"non_2xx\",\n                    kind = \"budget\",\n                    \"[backend_api] budget-exhausted 400 on {} {} — not reporting to Sentry\",","sourceCodeStart":762,"sourceCodeEnd":798,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/api/rest.rs#L762-L798","documentation":"A 404 on GET /announcements/latest is semantically \"no announcement right now\", so authed_json maps it to the typed AnnouncementNotFound; the announcements caller degrades to null instead of propagating an error. Best-effort cosmetic path, never reported to Sentry.","triggerScenarios":"Thrown at src/api/rest.rs:780 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Treat as the empty state — render no announcement","No corrective action needed; it clears when a new announcement is published"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}