Skip to content

Bug: cavemem start fails with spawn UNKNOWN on Windows #18

@julianfere

Description

@julianfere

Environment

  • OS: Windows 11 Pro (10.0.26200)
  • Node: v22.11.0
  • npm: 10.9.0
  • cavemem: 0.1.3
  • Shell: bash / PowerShell (both reproduce)

Steps to reproduce

  1. npm i -g cavemem
  2. Run cavemem start

Expected

Worker daemon starts, prints started (pid <N>) http://127.0.0.1:<port>.

Actual

cavemem error: spawn UNKNOWN

The worker never starts. The same code path also fires on cavemem restart and on ensureWorkerRunning autostart from hooks, so anything that tries to bring the worker up is broken on Windows.

Root cause

In dist/index.js, the worker is spawned by passing the CLI script path (a .js file) directly as the executable:

// dist/index.js:885 (startWorker)
const child = spawn3(resolveCliPath(), ["worker", "run"], {
  detached: true,
  stdio: "ignore",
  env: process.env
});

resolveCliPath() returns realpath(process.argv[1]), i.e. node_modules/cavemem/dist/index.js.

On Windows, child_process.spawn can't execute a .js file directly without shell: true. Since Node 20.12 (CVE-2024-27980), Windows spawn behavior is also stricter, so instead of silently delegating to the shell it throws spawn UNKNOWN.

Same pattern at dist/index.js:285 inside ensureWorkerRunning:

  const child = spawn2(cli, ["worker", "start"], {
    detached: true,
    stdio: "ignore",
    env: { ...process.env }
  });

Workaround

Spawn the Node binary explicitly via process.execPath and pass the script as the first argument. Also adding windowsHide: true to avoid a flashing console window on Windows.

  // dist/index.js:285 (ensureWorkerRunning)
  const child = spawn2(process.execPath, [cli, "worker", "start"], {
    detached: true,
    stdio: "ignore",
    env: { ...process.env },
    windowsHide: true
  });

  // dist/index.js:885 (startWorker)
  const child = spawn3(process.execPath, [resolveCliPath(), "worker", "run"], {
    detached: true,
    stdio: "ignore",
    env: process.env,
    windowsHide: true
  });

Verified locally — after patching, cavemem start prints:
started (pid 41176) http://127.0.0.1:37777
and the viewer is reachable.

I think it is somewhat related to #11, let me know if it is only a problem in my environment and it isn't a bug

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions