{"record":{"id":"6ab72508a1af16fb","repo":"Hmbown/CodeWhale","slug":"codewhale-credentials-directory-has-an-unsupported-component","errorCode":null,"errorMessage":"Codewhale credentials directory has an unsupported component: {}","messagePattern":"Codewhale credentials directory has an unsupported component: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":606,"sourceCode":"    // SAFETY: the literal root path contains no interior NUL and the returned\n    // descriptor is immediately owned by `File`.\n    let root_fd = unsafe {\n        libc::open(\n            c\"/\".as_ptr(),\n            libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC | libc::O_NOFOLLOW,\n        )\n    };\n    if root_fd < 0 {\n        return Err(std::io::Error::last_os_error()).context(\"opening filesystem root\");\n    }\n    // SAFETY: `root_fd` is a newly owned descriptor on the success path above.\n    let mut current = unsafe { File::from_raw_fd(root_fd) };\n    for component in directory.components() {\n        let Component::Normal(name) = component else {\n            if matches!(component, Component::RootDir) {\n                continue;\n            }\n            bail!(\n                \"Codewhale credentials directory has an unsupported component: {}\",\n                crate::quote_os_path(directory)\n            );\n        };\n        let name = cstring_from_os_str(name)?;\n        // SAFETY: parent borrowed from live `current`; `name` outlives the call.\n        let mut fd = unsafe {\n            libc::openat(\n                std::os::fd::AsRawFd::as_raw_fd(&current),\n                name.as_ptr(),\n                libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC | libc::O_NOFOLLOW,\n            )\n        };\n        if fd < 0 && std::io::Error::last_os_error().kind() == std::io::ErrorKind::NotFound {\n            // SAFETY: both the parent descriptor and component pointer remain\n            // valid for this call. `mkdirat` cannot follow the missing leaf.\n            let created = unsafe {\n                libc::mkdirat(","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/xai_credentials.rs#L588-L624","documentation":"open_owned_credentials_directory walks each component of the credentials directory path, opening pinned handles; only RootDir and Normal components are supported. Any other component kind (e.g. CurDir, ParentDir, or prefix components) is rejected because the store must pin real directory identity component by component.","triggerScenarios":"Opening the credential store (Store::open) or logout cleanup when the configured credentials directory contains `.` or `..` or other non-Normal components.","commonSituations":"Config path built with relative segments like `../.codewhale` or `./creds`; Windows paths with unsupported prefix components; env-derived paths not cleaned before use.","solutions":["Normalize the credentials directory path (canonicalize or strip `.`/`..`) before configuring it","Set the credentials directory to a plain absolute path with only normal components","Re-run with the corrected config value"],"exampleFix":"// before\nlet dir = PathBuf::from(\"/home/u/.config/../.codewhale/xai\");\n// after\nlet dir = PathBuf::from(\"/home/u/.codewhale/xai\");","handlingStrategy":"validation","validationCode":"fn has_only_normal_components(p: &std::path::Path) -> bool {\n    p.components().all(|c| matches!(c, std::path::Component::Normal(_) | std::path::Component::RootDir))\n}\nassert!(has_only_normal_components(&creds_dir));","typeGuard":"fn has_only_normal_components(p: &std::path::Path) -> bool {\n    p.components().all(|c| matches!(c, std::path::Component::Normal(_) | std::path::Component::RootDir))\n}","tryCatchPattern":"match Store::open(dir) {\n    Err(e) if e.to_string().contains(\"unsupported component\") => {\n        let dir = std::fs::canonicalize(dir)?;\n        Store::open(dir)\n    }\n    other => other,\n}","preventionTips":["Configure plain absolute paths for credential directories","Strip `.`/`..` segments when deriving paths from env vars","Test config paths on each target OS before shipping"],"tags":["path","validation","security"],"backgroundTag":"invalid-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}