{"record":{"id":"db7ffe93a972d196","repo":"Hmbown/CodeWhale","slug":"codewhale-owned-xai-oauth-path-was-redirected-whil","errorCode":null,"errorMessage":"Codewhale-owned xAI OAuth path was redirected while opening","messagePattern":"Codewhale-owned xAI OAuth path was redirected while opening","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":1239,"sourceCode":"    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 {\n        GetFinalPathNameByHandleW(handle, buffer.as_mut_ptr(), buffer.len() as u32, flags)\n    };\n    if written == 0 || written as usize >= buffer.len() {\n        return Err(std::io::Error::last_os_error())\n            .context(\"resolving Codewhale-owned xAI OAuth handle path\");\n    }\n    let actual = OsString::from_wide(&buffer[..written as usize]);\n    anyhow::ensure!(\n        normalize_windows_path_for_comparison(Path::new(&actual))?\n            == normalize_windows_path_for_comparison(expected)?,\n        \"Codewhale-owned xAI OAuth path was redirected while opening\"\n    );\n    Ok(metadata)\n}\n\n#[cfg(windows)]\nfn normalize_windows_path_for_comparison(path: &Path) -> Result<String> {\n    let text = path.to_str().ok_or_else(|| {\n        anyhow::anyhow!(\n            \"xAI OAuth path {} contains invalid Unicode and cannot be compared safely\",\n            crate::quote_os_path(path)\n        )\n    })?;\n    let without_device_prefix = text.strip_prefix(r\"\\\\?\\\").unwrap_or(text);\n    let normalized_prefix = without_device_prefix.strip_prefix(\"UNC\\\\\").map_or_else(\n        || without_device_prefix.to_string(),","sourceCodeStart":1221,"sourceCodeEnd":1257,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/config/src/xai_credentials.rs#L1221-L1257","documentation":"The windows opener resolves the handle's final path with GetFinalPathNameByHandleW (normalized, DOS volume names) and requires it to equal the expected lexical path after normalization. A mismatch means the open was redirected by a subst drive, a mapped network drive resolving to UNC, a junction in an ancestor, or case normalization, so the pinned directory identity no longer matches what was configured.","triggerScenarios":"CODEWHALE_HOME located under a subst drive letter, a mapped network drive (final path resolves to \\\\server\\share\\...), or an ancestor junction; 8.3 short-name components in the configured path that FILE_NAME_NORMALIZED expands.","commonSituations":"Corporate images with subst/mapped drives; roaming profiles; users setting CODEWHALE_HOME through short paths; home directories redirected via junctions.","solutions":["Set CODEWHALE_HOME to the resolved final path (the real UNC \\\\server\\share\\... form or the non-subst drive path)","Remove the subst/mapped-drive indirection over the home directory","After changing the variable, re-run codewhale auth xai-device so credentials are stored under the resolved path"],"exampleFix":":: before\nset CODEWHALE_HOME=X:\\codewhale        (X: is a subst/mapped drive)\n\n:: after\nsubst X: /d   (or disconnect the mapped drive)\nset CODEWHALE_HOME=C:\\Users\\me\\.codewhale\ncodewhale auth xai-device","handlingStrategy":"validation","validationCode":"// Resolve indirections before pointing CODEWHALE_HOME at a path\nlet resolved = std::fs::canonicalize(&dir)?;\nlet resolved = resolved\n    .to_str()\n    .map(|s| s.trim_start_matches(r\"\\\\?\\\").to_string())\n    .unwrap_or_else(|| resolved.display().to_string());\nanyhow::ensure!(!resolved.starts_with(\"\\\\\\\\\"), \"network paths and subst drives get redirected; use a local path\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set CODEWHALE_HOME to a plain local NTFS path without subst/mapped drives","Resolve the path once with canonicalize before configuring it","Avoid 8.3 short-name components in configured paths"],"tags":["windows","filesystem","path-resolution","security","xai-oauth"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}