[VS Code] Chat creation fails with "AbsolutePathBuf deserialized without a base path" when any workspace folder is virtual (non-`file` scheme) - uri.fsPath read without a scheme check
What version of the IDE extension are you using?
26.721.41059 (win32-x64). Also reproduces on 26.721.30844.
What subscription do you have?
API key / pay-as-you-go.
Which IDE are you using?
VS Code 1.131.0 (commit e4c7e7b1d6d060162f4aa7f8225271b67ce1df75, x64)
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What issue are you seeing?
Creating a new chat fails with:
Error creating chat
Invalid request: AbsolutePathBuf deserialized without a base path
whenever the VS Code window contains any workspace folder whose URI scheme is not file — i.e. a folder backed by a FileSystemProvider ([virtual workspace](<https://code.visualstudio.com/api/extension-guides/virtual-workspaces>)). It fails even when another, perfectly valid on-disk folder is also open.
Root cause: uri.fsPath is read without checking uri.scheme.
From the shipped bundle out/extension.js (26.721.41059):
function Xv(){let t=KSe.workspace.workspaceFolders?.map(r=>r.uri.fsPath)??[];return vr()?t.map(kr):t}
(identical code in 26.721.30844, minified as Qv). This feeds the active-workspace-roots and workspace-root-options handlers, which become { cwd: rootPaths[0], workspaceRoots: rootPaths }.
For a non-file scheme, Uri.fsPath does not return an absolute path. VS Code's URI._makeFsPath only applies the UNC/authority branch when scheme === 'file', so a virtual folder yields a drive-less, root-relative string:
<!-- linear:table-colwidths:266,266,266 -->
| workspace folder URI | uri.fsPath on Windows | absolute? |
| -- | -- | -- |
| vscode-vfs://github/microsoft/vscode | \microsoft\vscode | ❌ |
| myfs:/Root | \Root | ❌ |
| myfs-agent:/c%3A/Users/me/anchor (passthrough provider) | c:\Users\me\anchor | ✅ |
| file:///c:/Users/me/project | c:\Users\me\project | ✅ |
That non-absolute string is then sent as a workspace root, and the Rust core's AbsolutePathBuf deserializer rejects it. Because the failure happens while deserializing the whole request, it is all-or-nothing: one bad root kills chat creation instead of that root being skipped.
In my original case the workspace had two folders — the first one a real on-disk directory (valid c:\... path), the second one virtual. Chat creation still failed, even though a usable root was present and first in the list.
What steps can reproduce the bug?
Reproducible with a public, Microsoft-published extension — no private code needed:
- Install [GitHub Repositories](<https://marketplace.visualstudio.com/items?itemName=GitHub.remotehub>) (
GitHub.remotehub) — the extension used as the reference example in VS Code's own virtual-workspace docs. - Run Open GitHub Repository… from the Command Palette and open any repository. The window now has a
vscode-vfs://github/<owner>/<repo>folder. - (Optional, to show it fails even with a valid root) File → Add Folder to Workspace… and add any normal on-disk folder, so folder\[0\] is a valid
file:path. - Open the Codex panel and send any prompt.
Result: Error creating chat — Invalid request: AbsolutePathBuf deserialized without a base path
The same happens for any .code-workspace that lists a folder with a custom scheme, e.g.:
{
"folders": [
{ "name": "Local", "uri": "file:///c%3A/Users/me/project" },
{ "name": "Virtual", "uri": "myfs:/Root" }
]
}
What is the expected behavior?
Roots that cannot be a native working directory should be dropped before the request is sent, so chat opens using whatever valid roots remain. If none remain, the existing "Add a project to use Codex" empty state is the right thing to show — not an internal deserialization error.
The predicate should be "is this a fully-qualified native path?", i.e. exactly the AbsolutePathBuf contract the core already requires — not a proxy for it. Two obvious-looking alternatives are both wrong:
<!-- linear:table-colwidths:200,200,200,200 -->
| candidate predicate | myfs-agent:/c%3A/… (passthrough onto a real dir) | myfs:/Root | verdict |
| -- | -- | -- | -- |
| uri.scheme === 'file' | ❌ dropped, though it is a perfectly good working dir | ✅ dropped | too strict |
| path.isAbsolute(p) | ✅ kept | ❌ kept — on Windows path.win32.isAbsolute('\\Root') is true | too loose |
| fully-qualified (drive-rooted or UNC) | ✅ kept | ✅ dropped | ✅ correct |
path.isAbsolute is worth calling out explicitly: on Windows it accepts drive-relative paths like \Root, so it would let the exact value that breaks AbsolutePathBuf straight through.
The scheme check is too strict because a FileSystemProvider may legitimately be a passthrough onto a real directory and deliberately shape its URI so that uri.fsPath yields a valid native path — precisely so that agents deriving a cwd from workspaceFolders[…].uri.fsPath keep working, while the window still counts as a virtual workspace (which ms-python.python and ms-python.vscode-pylance key their behaviour off). Filtering purely on scheme would break that arrangement and leave the extension with zero roots.
Suggested shape:
const isFullyQualified = p => /^[a-zA-Z]:[\\/]/.test(p) || p.startsWith('\\\\'); // POSIX: p.startsWith('/')
const roots = (vscode.workspace.workspaceFolders ?? [])
.map(f => f.uri.fsPath)
.filter(isFullyQualified);
Related VS Code guidance, which is why fsPath cannot be trusted unconditionally in the first place:
Never assume that the URI scheme isfile.URI.fsPathcan only be used when the URI scheme isfile. — [https://code.visualstudio.com/api/extension-guides/virtual-workspaces](<https://code.visualstudio.com/api/extension-guides/virtual-workspaces>)
A note on the shape of the fix: simply taking workspaceFolders[0] as cwd without a scheme check is not a sufficient alternative. I checked a neighbouring extension that does exactly that (fs.realpathSync(folders.map(f => f.uri.fsPath)[0] || os.homedir()), no filter, no try/catch) and it merely fails differently: it happens to work when folder\[0\] is a real directory, but throws when the virtual folder comes first — on Windows fs.realpathSync("\\microsoft\\vscode") raises UNKNOWN, and fs.realpathSync("\\Root") raises ENOENT: lstat "C:\\Root". Ordering luck, not robustness. The scheme filter is what actually makes this correct in every ordering.
Worth stressing that the Codex variant is the harsher one: it fails even when a valid on-disk root is present and is first in the list, because the non-absolute entry breaks deserialization of the entire request rather than just that one root.
Additional information
- Impact is not limited to one extension. Any
FileSystemProviderputs the window in this state: GitHub Repositories / Remote Repositories (vscode-vfs:), Azure Repos, WSL-less remote browsers, and third-party providers. Users hit it as soon as one such folder is present. capabilities.virtualWorkspacesis not declared in the extension'spackage.json. Per the docs, an extension that doesn't declare it is treated as supporting virtual workspaces, so VS Code happily activates Codex in precisely the configuration where it breaks. Alongside the scheme filter, declaring"supported": "limited"with a short description would set correct expectations.- The error message is opaque.
AbsolutePathBuf deserialized without a base pathgives no indication that a workspace folder is at fault. Including the offending path in the error would have saved a lot of debugging; this also seems to be the common thread across openai/codex#23209, openai/codex#23213, openai/codex#27567, openai/codex#31983 and openai/codex#32474. - Not a duplicate of openai/codex#23213 (fails in all workspaces, including plain
file:ones) or openai/codex#16815 / openai/codex#29454 (WSL agent mode). Closest related: openai/codex#35260 and [#2909](<https://github.com/openai/codex/issues/2909>). openai/codex#5323 touched virtual workspace roots but from the search-scoping angle. - Side observation (from reading
kr(), not verified — no WSL on this machine): in WSL mode the path converter's fallback maps\Root→/Root, which is POSIX-absolute, so the same workspace may appear to work there. That would mask the missing scheme check rather than fix it.
1 Comment
Confirming this also reproduces in a plain VS Code Dev Containers setup (not just Codespaces/virtual-FS/Azure Repos) — worth noting since the root cause generalizes beyond those.
Repro environment:
ghcr.io/devcontainers/*features,python:3.12base image)./workspaces/<repo>inside the container.Error creating chat / Invalid request: AbsolutePathBuf deserialized without a base path.Diagnostics that rule out a network/auth cause (in case it helps triage — this presents identically to a connectivity failure but isn't one):
api.openai.comandchatgpt.comresolve correctly, valid certs, no proxy/MITM in the container.chatgpt.com/backend-api/codex/responsesresponds normally (401unauthenticated, i.e. reachable).codex login --device-auth(CLI) completes the device-code handshake againstauth.openai.comwithout issue.Matches the diagnosis in this issue: when the extension host runs remotely (which is exactly what a Dev Container is), the workspace folder URI is
vscode-remote://dev-container+…/workspaces/<repo>rather thanfile://…, anduri.fsPathis read without checking that scheme.Workaround confirmed: running the standalone
codexCLI in the container's integrated terminal (npm i -g @openai/codex) works fine — it resolves its own cwd directly rather than going through the extension's workspace-folder URI handling, so it never hits this code path. That's a viable stopgap for anyone hitting this in a Dev Container until the fix lands.