Short description
On Windows, every LSP server spawn fails because the daemon passes a \\?\-prefixed (extended-length) project root as the child process working directory. CreateProcess does not support extended-length paths in lpCurrentDirectory (documented Win32 limitation), so the spawn dies with ERROR_PATH_NOT_FOUND → "The system cannot find the path specified." → AFT reports all LSP servers as not installed/unusable.
Observed behavior
aft-opencode v0.49.0, Windows 10 0.26100, project root C:\Users\Sanveed:
[aft-lsp] [ses_...] failed to spawn TypeScript Language Server: server not ready: server crashed during initialize: server not ready: language server TypeScript disconnected while waiting for 'initialize'; stderr (last 64 lines):
The system cannot find the path specified.
[aft] ... exited TypeScript \\?\C:\Users\Sanveed
- The server package is installed and healthy:
typescript-language-server --version → 5.3.0, and a full LSP initialize handshake succeeds when spawned with a normal cwd.
aft_inspect reports "servers: not installed" because the daemon can't spawn them.
- The same
\\?\ root also breaks unrelated child spawns in that session, e.g. artifact cache key: git root-commit probe failed after retries (spawn failed: program not found).
Root cause (source-verified, current main)
crates/aft/src/lsp/roots.rs:13 — find_workspace_root calls std::fs::canonicalize(file_path). On Windows, Rust's canonicalize returns \\?\-prefixed extended-length paths (e.g. \\?\C:\Users\Sanveed).
crates/aft/src/lsp/manager.rs — that root flows into LspClient::spawn → crates/aft/src/lsp/client.rs:165 — .current_dir(&root).
CreateProcess with lpCurrentDirectory = \\?\... → ERROR_PATH_NOT_FOUND.
Independent repro (same error class through .NET's Process.Start, which uses CreateProcess):
cwd=C:\Users\Sanveed => STARTED ok
cwd=\\?\C:\Users\Sanveed => FAILED: "The directory name is invalid"
Note the codebase already strips \\?\ for URI conversion (position.rs:160-170), and the opencode plugin's normalizeWindowsRoot() does the same for project-root canonicalization — but the LSP spawn cwd path is not normalized.
Expected behavior
LSP servers spawn successfully on Windows. Either:
- strip the
\\?\ prefix from the root before .current_dir(), or
- avoid
canonicalize for the workspace root on Windows (walk-up marker search works fine on non-canonical paths).
Environment
- AFT plugin: 0.49.0 / aft binary 0.49.0
- OS: Windows 10 22H2 (26100), x64
- Host: OpenCode, aft-opencode plugin
- Affects every session regardless of project (any absolute path canonicalizes to
\\?\ on Windows)
Short description
On Windows, every LSP server spawn fails because the daemon passes a
\\?\-prefixed (extended-length) project root as the child process working directory.CreateProcessdoes not support extended-length paths inlpCurrentDirectory(documented Win32 limitation), so the spawn dies withERROR_PATH_NOT_FOUND→ "The system cannot find the path specified." → AFT reports all LSP servers as not installed/unusable.Observed behavior
aft-opencode v0.49.0, Windows 10 0.26100, project root
C:\Users\Sanveed:typescript-language-server --version→5.3.0, and a full LSP initialize handshake succeeds when spawned with a normal cwd.aft_inspectreports "servers: not installed" because the daemon can't spawn them.\\?\root also breaks unrelated child spawns in that session, e.g.artifact cache key: git root-commit probe failed after retries (spawn failed: program not found).Root cause (source-verified, current main)
crates/aft/src/lsp/roots.rs:13—find_workspace_rootcallsstd::fs::canonicalize(file_path). On Windows, Rust'scanonicalizereturns\\?\-prefixed extended-length paths (e.g.\\?\C:\Users\Sanveed).crates/aft/src/lsp/manager.rs— that root flows intoLspClient::spawn→crates/aft/src/lsp/client.rs:165—.current_dir(&root).CreateProcesswithlpCurrentDirectory = \\?\...→ERROR_PATH_NOT_FOUND.Independent repro (same error class through .NET's Process.Start, which uses CreateProcess):
Note the codebase already strips
\\?\for URI conversion (position.rs:160-170), and the opencode plugin'snormalizeWindowsRoot()does the same for project-root canonicalization — but the LSP spawn cwd path is not normalized.Expected behavior
LSP servers spawn successfully on Windows. Either:
\\?\prefix from the root before.current_dir(), orcanonicalizefor the workspace root on Windows (walk-up marker search works fine on non-canonical paths).Environment
\\?\on Windows)