Skip to content

Windows paths from SSE clients not converted on Linux/WSL — corrupts database, crashes server, 100% WSL CPU #36902

Description

@hmnijp

Related issues: #16680, #15719, #27879, #30895, #33107
Related PR: #34256

Description

Running opencode web or opencode serve inside WSL breaks as soon as a Windows browser or Desktop client connects. The SSE /event?directory= endpoint receives native Windows paths (C:\Users\K\...), but the path normalization function windowsPath() is a no-op on Linux. These raw Windows paths get concatenated with the server working directory (producing garbage like /home/k/opencode/C:\...) and written into the SQLite database.

On restart, Project.list() crashes: Path.isAbsolute("C:/Users/...") returns false on Linux, and the code's fallback check is gated behind process.platform === "win32".

The resulting error/retry loop saturates the WSL VM to 100% CPU, freezing both the opencode server and the entire WSL environment. This makes opencode web / opencode serve in WSL completely unusable — the very act of connecting from Windows destroys the server's ability to function.

Root Cause

Two functions are platform-gated to Windows only:

packages/core/src/fs-util.ts:147windowsPath() skips conversion on Linux/WSL:

export function windowsPath(p: string): string {
  if (process.platform !== "win32") return p
  // ...
}

When a Windows client sends ?directory=C:\Users\K\..., this function returns the path unchanged. path.resolve() then treats it as relative to CWD, producing /home/k/opencode/C:\Users\K\....

packages/core/src/database/path.ts:14-18absolute() rejects Windows paths on Linux:

function absolute(input: string) {
  const result = storagePath(input)
  if (!nodePath.posix.isAbsolute(result) &&
      !(process.platform === "win32" && isWindowsStoragePath(result))) {
    throw new Error(`Path is not absolute: ${input}`)
  }
}

The isWindowsStoragePath() function would correctly identify C:/... as valid, but it's never consulted because the outer process.platform === "win32" guard is false on Linux.

Log Evidence

ERROR message=failed ref=err_a576f06d
  error="EffectDrizzleQueryError: Failed query: select ... from \"project\"
         (cause: Cause([Fail(Error: Path is not absolute: C:/Users/K/Documents/INFO)]))"
INFO  message="creating instance" directory=/home/k/opencode/C:/Users/K/Documents/test-opencode
INFO  message="fromDirectory"     directory=/home/k/opencode/C:/Users/K/Documents/test-opencode
WARN  message="failed to initialize fff" error="Invalid path C:/Users/K/Documents/test-opencode"
ERROR message="FileSystem.realPath (C:/Users/K/Documents/test-opencode)" error="ENOENT: no such file or directory"
INFO  message="global event connected"
INFO  message="creating instance" directory="/home/k/opencode/C:\\Users\\K\\Documents\\test-opencode"

Plugins

none

OpenCode version

1.17.20 (tested on Linux binary, WSL Debian, Windows binary)

Steps to reproduce

  1. Install opencode inside WSL (Debian/Ubuntu), start opencode web with a clean state
  2. Open http://localhost:3030 in a Windows browser (or use Windows Desktop with remote server configured to WSL)
  3. Immediately — within seconds of the browser loading — the SSE /event?directory= endpoint receives the frontend's native Windows path:
    ?directory=C:\Users\K\Documents\my-project
    
  4. Server's windowsPath() is a no-op on Linux. path.resolve() treats it as relative to CWD:
    → "/home/k/opencode/C:\Users\K\Documents\my-project"
    
  5. Server logs "creating instance" directory=/home/k/opencode/C:\Users\K\Documents\my-project
  6. Project.fromDirectory() writes the garbage path to SQLite project table
  7. FSUtil.resolve() immediately fails with ENOENT on realPath(C:/Users/K/...) because the path doesn't exist on Linux
  8. FFF initialization fails with "Invalid path C:/Users/K/Documents/my-project"
  9. Server enters tight error/retry loop — keeps attempting operations on the garbage path → WSL VM spikes to 100% CPU within seconds

The problem manifests on the very first Windows client connection.

Screenshot and/or share link

none

Operating System

Windows 11 host, WSL2 Debian guest (Linux kernel via wsl)

Terminal

WSL terminal (Debian), opencode web process

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions