{"record":{"id":"d114cd0213afc0f7","repo":"astrid-runtime/astrid","slug":"no-free-windows-drive-target-is-available-specify","errorCode":null,"errorMessage":"no free Windows drive target is available; specify a directory mountpoint","messagePattern":"no free Windows drive target is available; specify a directory mountpoint","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/main.rs","lineNumber":405,"sourceCode":"    bail!(\"the WinFsp provider is available only on Windows\")\n}\n\n#[cfg(windows)]\nfn first_free_drive() -> Result<PathBuf> {\n    for letter in b'D'..=b'Z' {\n        let root = PathBuf::from(format!(\"{}:\\\\\", letter as char));\n        match std::fs::metadata(&root) {\n            Ok(_) => {},\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {\n                return Ok(root);\n            },\n            Err(error) => {\n                return Err(error)\n                    .context(format!(\"inspect Windows drive target {}\", root.display()));\n            },\n        }\n    }\n    bail!(\"no free Windows drive target is available; specify a directory mountpoint\")\n}\n\n#[cfg(windows)]\nfn is_drive_target(path: &Path) -> bool {\n    let Some(text) = path.to_str() else {\n        return false;\n    };\n    let bytes = text.as_bytes();\n    bytes.len() == 3\n        && bytes[0].is_ascii_alphabetic()\n        && bytes[1] == b':'\n        && (bytes[2] == b'\\\\' || bytes[2] == b'/')\n}\n\n#[cfg(windows)]\nasync fn native_mount(lease: &StorageMountLeaseV1, mountpoint: &Path) -> Result<()> {\n    win::spawn_daemon(lease, mountpoint).await\n}","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/main.rs#L387-L423","documentation":"first_free_drive scans candidate drive-letter targets and bails when none of them is a usable free Windows drive target. The library refuses to silently pick or reuse a letter; it requires the caller to supply an explicit directory mountpoint instead. This keeps drive-letter assignment deterministic and user-controlled.","triggerScenarios":"Calling the WinFsp provider for a drive-letter mount when every candidate drive letter is already mapped, is not a valid drive target (is_drive_target fails), or cannot be inspected (stat on the root fails for all candidates).","commonSituations":"Machines with many mapped network drives or subst/DevDrive letters consuming most of A-Z; running in containers or CI where drive enumeration returns nothing; passing a drive-letter mount config on a system with no free letters.","solutions":["Pass an explicit directory mountpoint (e.g. C:\\mounts\\astrid) instead of relying on automatic drive-letter selection","Free a drive letter: unmap unused network drives (net use X: /delete) or remove subst mappings","Check which letters are taken with `net use` / Disk Management and confirm at least one candidate is free","Inspect the wrapped error context ('inspect Windows drive target ...') to see which candidate failed and why"],"exampleFix":"// before\nlet opts = MountOptions { mountpoint: None, .. };\nprovider.mount(opts)?; // picks a drive letter, fails when none free\n// after\nlet opts = MountOptions { mountpoint: Some(PathBuf::from(\"C:\\\\mounts\\\\astrid\")), .. };\nprovider.mount(opts)?;","handlingStrategy":"validation","validationCode":"fn ensure_mount_target_ok(mp: &Path) -> Result<(), String> {\n    if mp.is_dir() { return Ok(()); }\n    let letter = mp.to_str().ok_or(\"mountpoint not valid UTF-8\")?;\n    let drive = letter.trim_end_matches('\\\\');\n    if drive.len() == 2 && drive.as_bytes()[1] == b':' && std::fs::metadata(drive).is_err() {\n        return Ok(()); // free drive letter\n    }\n    Err(\"no free drive letter; pass an explicit directory mountpoint\".into())\n}","typeGuard":"fn is_free_drive_designator(s: &str) -> bool {\n    let b = s.as_bytes();\n    b.len() == 2 && b[1] == b':' && std::fs::metadata(&s[..2]).is_err()\n}","tryCatchPattern":"match provider.mount(opts) {\n    Err(e) if e.to_string().contains(\"no free Windows drive target\") => {\n        mount_with_directory_fallback(opts)?;\n    }\n    other => other?,\n}","preventionTips":["Always configure an explicit directory mountpoint in automated/CI environments","Audit mapped drives (net use, subst) before drive-letter mounts","Map the wrapped 'inspect Windows drive target' contexts to identify blocked letters"],"tags":["windows","winfsp","filesystem","mount"],"backgroundTag":"resource-not-found","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}