{"record":{"id":"dcefd1caf719c807","repo":"Hmbown/CodeWhale","slug":"runtime-api-returned-status","errorCode":null,"errorMessage":"runtime API returned {status}","messagePattern":"runtime API returned (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/app-server/src/lib.rs","lineNumber":1109,"sourceCode":"            }\n        }\n    }\n\n    fn authed(&self, builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {\n        match self.auth_token.as_deref() {\n            Some(token) => builder.bearer_auth(token),\n            None => builder,\n        }\n    }\n\n    async fn request_json(&self, builder: reqwest::RequestBuilder) -> Result<Value> {\n        let response = builder.send().await?;\n        let status = response.status();\n        let body = response.text().await?;\n        if !status.is_success() {\n            let detail = body.trim();\n            if detail.is_empty() {\n                bail!(\"runtime API returned {status}\");\n            }\n            bail!(\"runtime API returned {status}: {detail}\");\n        }\n        serde_json::from_str(&body).with_context(|| format!(\"invalid runtime API json: {body}\"))\n    }\n\n    async fn ensure_runtime_thread(\n        &mut self,\n        stdio_thread_id: &str,\n        hint: Option<RuntimeThreadHint>,\n    ) -> Result<String> {\n        if let Some(runtime_thread_id) = self.thread_map.get(stdio_thread_id) {\n            return Ok(runtime_thread_id.clone());\n        }\n        let hint = hint.unwrap_or_default();\n        let runtime_thread_id = self\n            .create_runtime_thread(hint.model, hint.workspace)\n            .await?;","sourceCodeStart":1091,"sourceCodeEnd":1127,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/app-server/src/lib.rs#L1091-L1127","documentation":"SessionManager normalizes its managed (sessions) directory before use: normalize_managed_dir rejects an empty path immediately with InvalidInput - an empty OsString cannot name a directory - then rejects relative paths containing traversal components, and finally anchors plain relative paths to the current directory.","triggerScenarios":"Constructing SessionManager (which calls normalize_managed_dir at session_manager.rs:1022) with an empty sessions_dir PathBuf: a config value like sessions_dir = \"\", a blank environment override, or Option::unwrap_or_default() on a missing setting (PathBuf's default is empty).","commonSituations":"Config templating that leaves a path key present but blank; env var set to an empty string; code defaulting a missing optional path to PathBuf::new() instead of a real default directory.","solutions":["Set sessions_dir to a real path, or remove the empty override so the built-in default applies","Replace unwrap_or_default() with unwrap_or_else(default_sessions_dir) for optional path settings","Validate path-valued config at load time and reject blank strings with a clear field name"],"exampleFix":"// before\nlet dir = cfg.sessions_dir.clone().unwrap_or_default();\n\n// after\nlet dir = cfg.sessions_dir.clone().unwrap_or_else(default_sessions_dir);","handlingStrategy":"validation","validationCode":"fn managed_dir_is_valid(p: &std::path::Path) -> bool {\n    !p.as_os_str().is_empty()\n}","typeGuard":"fn is_non_empty_dir_path(p: &std::path::Path) -> bool { !p.as_os_str().is_empty() }","tryCatchPattern":"match normalize_managed_dir(dir.clone()) {\n    Err(e) if e.to_string().contains(\"cannot be empty\") => {\n        // fail config load naming the sessions_dir field; require a real path or the default\n    }\n    other => other?,\n}","preventionTips":["Reject blank strings for path-valued config keys at load time","Use unwrap_or_else(default_dir), never unwrap_or_default(), for optional paths","Trim and validate env-var overrides before they become directories"],"tags":["config","path-validation","invalid-input","sessions"],"backgroundTag":"empty-path-config","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}