{"record":{"id":"bbcdad0cba183681","repo":"Hmbown/CodeWhale","slug":"shared-pet-connection-failed","errorCode":null,"errorMessage":"Shared pet connection failed","messagePattern":"Shared pet connection failed","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/live.rs","lineNumber":222,"sourceCode":"            .map_err(io::Error::other)?;\n        let status = response.status();\n        let success = status.is_success();\n        let bound = if path == \"/v1/export\" {\n            super::persistence::MAX_EXPORT_BYTES\n        } else {\n            8 * 1024 * 1024\n        };\n        let mut bytes = Vec::new();\n        response.take(bound as u64 + 1).read_to_end(&mut bytes)?;\n        if bytes.len() > bound {\n            return Err(io::Error::other(\"Pet response exceeds its bound\"));\n        }\n        let value: Value = serde_json::from_slice(&bytes)?;\n        if !success {\n            let message = value[\"error\"]\n                .as_str()\n                .unwrap_or(\"Shared pet connection failed\");\n            return Err(io::Error::new(\n                if status == reqwest::StatusCode::CONFLICT && !message.contains(\"storage\") {\n                    io::ErrorKind::InvalidInput\n                } else {\n                    io::ErrorKind::Other\n                },\n                message,\n            ));\n        }\n        Ok(value)\n    }\n    pub fn open_browser(&self) -> io::Result<()> {\n        let url = format!(\n            \"http://127.0.0.1:{}/#{}\",\n            self.descriptor.port, self.descriptor.token\n        );\n        webbrowser::open(&url).map_err(io::Error::other)\n    }\n    pub fn open_window(&self) -> io::Result<()> {","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/live.rs#L204-L240","documentation":"This io::Error is returned by the shared-pet HTTP client in pet_watch/live.rs when the server responds with a non-success status. It carries the server's `error` message string (falling back to the generic text), and maps a 409 CONFLICT whose message does not mention 'storage' to ErrorKind::InvalidInput; all other failures map to ErrorKind::Other.","triggerScenarios":"Any request through the shared-pet API (request(), used by runner_request, public_request, get, post) that gets resp.success() == false — e.g. 409 conflict on concurrent pet updates, 4xx/5xx from the shared pet backend.","commonSituations":"Two clients writing the same shared pet state concurrently (409), shared-pet service outage returning 500, auth/permission rejection from the remote endpoint, offline network yielding a gateway error.","solutions":["Read the error's message: it is the server's `error` field — fix the condition it names (e.g. retry later on a storage-related 409 conflict).","Check connectivity/availability of the shared pet service before or after failure.","Retry with backoff for transient 5xx; treat ErrorKind::InvalidInput (409 non-storage) as a request problem, not a retry.","Fall back to local-only pet state when the shared connection fails."],"exampleFix":"// before\nlet pet = shared.get(pet_id)?;\n// after\nlet pet = match shared.get(pet_id) {\n    Ok(p) => p,\n    Err(e) if e.kind() == io::ErrorKind::Other => { log::warn!(\"shared pet unavailable: {e}\"); local_pet() }\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"// optionally probe first\nlet healthy = shared.get(health_path).is_ok();","typeGuard":null,"tryCatchPattern":"match shared.post(url, &body) {\n    Err(e) if e.kind() == io::ErrorKind::Other => retry_with_backoff(),\n    Err(e) => return Err(e),\n    Ok(v) => Ok(v),\n}","preventionTips":["Check server error messages, which are surfaced verbatim in the io::Error.","Retry only transient (Other/5xx) failures, not InvalidInput (409 non-storage).","Monitor shared-pet service health before batch operations."],"tags":["network","http","io"],"backgroundTag":"http-error-response","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}