{"record":{"id":"09a1b3b511430a85","repo":"Hmbown/CodeWhale","slug":"codewhale-owned-xai-oauth-path-has-the-wrong-files","errorCode":null,"errorMessage":"Codewhale-owned xAI OAuth path has the wrong filesystem type","messagePattern":"Codewhale-owned xAI OAuth path has the wrong filesystem type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":1213,"sourceCode":"    use std::os::windows::ffi::OsStringExt as _;\n    use std::os::windows::fs::MetadataExt as _;\n    use std::os::windows::io::AsRawHandle as _;\n    use windows_sys::Win32::Storage::FileSystem::{\n        FILE_ATTRIBUTE_REPARSE_POINT, FILE_NAME_NORMALIZED, GetFinalPathNameByHandleW,\n        VOLUME_NAME_DOS,\n    };\n\n    let metadata = file.metadata().with_context(|| {\n        format!(\n            \"inspecting Codewhale-owned path {}\",\n            crate::quote_os_path(expected)\n        )\n    })?;\n    anyhow::ensure!(\n        metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT == 0,\n        \"Codewhale-owned xAI OAuth path must not be a reparse point\"\n    );\n    anyhow::ensure!(\n        if expect_directory {\n            metadata.is_dir()\n        } else {\n            metadata.is_file()\n        },\n        \"Codewhale-owned xAI OAuth path has the wrong filesystem type\"\n    );\n    let flags = FILE_NAME_NORMALIZED | VOLUME_NAME_DOS;\n    let handle = file.as_raw_handle();\n    // SAFETY: null output asks only for the required UTF-16 length.\n    let needed = unsafe { GetFinalPathNameByHandleW(handle, std::ptr::null_mut(), 0, flags) };\n    if needed == 0 {\n        return Err(std::io::Error::last_os_error())\n            .context(\"resolving Codewhale-owned xAI OAuth handle path\");\n    }\n    let mut buffer = vec![0u16; needed as usize + 1];\n    // SAFETY: the buffer is writable and the handle remains valid.\n    let written = unsafe {","sourceCodeStart":1195,"sourceCodeEnd":1231,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/config/src/xai_credentials.rs#L1195-L1231","documentation":"After the reparse check, validate_windows_handle_path verifies the handle's filesystem type against expectation: directory components (expect_directory=true) must be directories and credential files must be regular files. It catches wrong-shaped entries created by leftover files or scripts pre-creating paths.","triggerScenarios":"$CODEWHALE_HOME/credentials exists as a regular file: fs::create_dir hits AlreadyExists, the later handle opens the file with BACKUP_SEMANTICS, and is_dir() is false; or a generation name (xai-auth-...json) exists as a directory.","commonSituations":"A leftover empty file named `credentials` from older tooling or a manual touch; scripts pre-creating the wrong path shape.","solutions":["Check what the path really is (Get-Item / fsutil), then remove the wrong-typed entry and re-run codewhale auth xai-device so the store recreates it correctly","Do not pre-create $CODEWHALE_HOME/credentials manually"],"exampleFix":"# before (PowerShell)\nGet-Item \"$env:USERPROFILE\\.codewhale\\credentials\"   # a file, not a directory\n\n# after\nRemove-Item \"$env:USERPROFILE\\.codewhale\\credentials\"\ncodewhale auth xai-device   # store recreates it as a directory","handlingStrategy":"validation","validationCode":"match std::fs::metadata(&dir) {\n    Ok(m) if m.is_dir() => Ok(()),\n    Ok(_) => anyhow::bail!(\"{} exists but is not a directory\", dir.display()),\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),\n    Err(e) => Err(e.into()),\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pre-create the credentials path manually","After backups or migrations, verify the path is a directory before logging in","Delete wrong-shaped leftovers instead of renaming them into place"],"tags":["windows","filesystem","validation","xai-oauth"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}