0
Fork 0
mirror of https://github.com/obra/superpowers.git synced 2026-09-25 22:09:05 +00:00

SessionStart hook crashes on Windows without WSL #440

Closed
opened 2026-02-08 15:12:09 +00:00 by hananMedDevSoft · 2 comments
hananMedDevSoft commented 2026-02-08 15:12:09 +00:00 (Migrated from github.com)

Problem

The SessionStart hook (hooks/session-start.sh) fails on Windows machines that don't have WSL installed. Claude Code attempts to execute the bash script via WSL, which produces:

<3>WSL (10) ERROR: CreateProcessCommon:559: execvpe(/bin/bash) failed: No such file or directory

This error occurs on every session startup, resume, clear, and compact event.

Environment

  • Platform: Windows 10/11
  • WSL: Not installed
  • Claude Code version: 2.1.x+
  • Superpowers plugin version: 4.2.0
  • Node.js: Available (v20.x)

Root Cause

In hooks/hooks.json, the command points directly to the .sh file:

{
  "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh",
  "async": true
}

Claude Code 2.1.x auto-detects .sh files and prepends bash on Windows. Without WSL or Git Bash's bash on PATH, this fails. The deprecated run-hook.cmd polyglot wrapper notes this behavior change but the current setup still relies on bash being available.

Suggested Fix

Add a session-start.js Node.js equivalent alongside the bash script, and use it on Windows. Node.js is guaranteed to be available since Claude Code itself requires it.

Here's the Node.js port that produces identical output:

const fs = require('fs');
const path = require('path');

const pluginRoot = path.resolve(__dirname, '..');

let warningMessage = '';
const legacySkillsDir = path.join(
  process.env.HOME || process.env.USERPROFILE || '',
  '.config', 'superpowers', 'skills'
);
try {
  if (fs.statSync(legacySkillsDir).isDirectory()) {
    warningMessage = '\n\n<important-reminder>IN YOUR FIRST REPLY AFTER SEEING THIS MESSAGE YOU MUST TELL THE USER:\u26a0\ufe0f **WARNING:** Superpowers now uses Claude Code\'s skills system. Custom skills in ~/.config/superpowers/skills will not be read. Move custom skills to ~/.claude/skills instead. To make this message go away, remove ~/.config/superpowers/skills</important-reminder>';
  }
} catch {
  // Directory doesn't exist
}

let content;
try {
  content = fs.readFileSync(
    path.join(pluginRoot, 'skills', 'using-superpowers', 'SKILL.md'),
    'utf8'
  );
} catch (err) {
  content = 'Error reading using-superpowers skill: ' + err.message;
}

const output = {
  hookSpecificOutput: {
    hookEventName: 'SessionStart',
    additionalContext:
      '<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n' +
      "**Below is the full content of your 'superpowers:using-superpowers' skill " +
      "- your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n" +
      content + '\n\n' + warningMessage + '\n</EXTREMELY_IMPORTANT>'
  }
};

process.stdout.write(JSON.stringify(output));

Then update hooks.json to use the Node.js script:

{
  "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\"",
  "async": true
}

Alternatively, hooks.json could use platform-conditional commands if Claude Code supports that, or detect the platform at runtime.

Workaround

Users can manually:

  1. Create hooks/session-start.js with the above content
  2. Edit hooks/hooks.json to point to the .js file
  3. Restart Claude Code

Tested and confirmed working on Windows with Node.js v20.x.

## Problem The `SessionStart` hook (`hooks/session-start.sh`) fails on Windows machines that don't have WSL installed. Claude Code attempts to execute the bash script via WSL, which produces: ``` <3>WSL (10) ERROR: CreateProcessCommon:559: execvpe(/bin/bash) failed: No such file or directory ``` This error occurs on every session startup, resume, clear, and compact event. ## Environment - Platform: Windows 10/11 - WSL: Not installed - Claude Code version: 2.1.x+ - Superpowers plugin version: 4.2.0 - Node.js: Available (v20.x) ## Root Cause In `hooks/hooks.json`, the command points directly to the `.sh` file: ```json { "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh", "async": true } ``` Claude Code 2.1.x auto-detects `.sh` files and prepends `bash` on Windows. Without WSL or Git Bash's `bash` on PATH, this fails. The deprecated `run-hook.cmd` polyglot wrapper notes this behavior change but the current setup still relies on bash being available. ## Suggested Fix Add a `session-start.js` Node.js equivalent alongside the bash script, and use it on Windows. Node.js is guaranteed to be available since Claude Code itself requires it. Here's the Node.js port that produces identical output: ```js const fs = require('fs'); const path = require('path'); const pluginRoot = path.resolve(__dirname, '..'); let warningMessage = ''; const legacySkillsDir = path.join( process.env.HOME || process.env.USERPROFILE || '', '.config', 'superpowers', 'skills' ); try { if (fs.statSync(legacySkillsDir).isDirectory()) { warningMessage = '\n\n<important-reminder>IN YOUR FIRST REPLY AFTER SEEING THIS MESSAGE YOU MUST TELL THE USER:\u26a0\ufe0f **WARNING:** Superpowers now uses Claude Code\'s skills system. Custom skills in ~/.config/superpowers/skills will not be read. Move custom skills to ~/.claude/skills instead. To make this message go away, remove ~/.config/superpowers/skills</important-reminder>'; } } catch { // Directory doesn't exist } let content; try { content = fs.readFileSync( path.join(pluginRoot, 'skills', 'using-superpowers', 'SKILL.md'), 'utf8' ); } catch (err) { content = 'Error reading using-superpowers skill: ' + err.message; } const output = { hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: '<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n' + "**Below is the full content of your 'superpowers:using-superpowers' skill " + "- your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n" + content + '\n\n' + warningMessage + '\n</EXTREMELY_IMPORTANT>' } }; process.stdout.write(JSON.stringify(output)); ``` Then update `hooks.json` to use the Node.js script: ```json { "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\"", "async": true } ``` Alternatively, `hooks.json` could use platform-conditional commands if Claude Code supports that, or detect the platform at runtime. ## Workaround Users can manually: 1. Create `hooks/session-start.js` with the above content 2. Edit `hooks/hooks.json` to point to the `.js` file 3. Restart Claude Code Tested and confirmed working on Windows with Node.js v20.x.
riperok commented 2026-02-13 23:56:52 +00:00 (Migrated from github.com)

Same issue, slightly different scenario: WSL installed for Docker Desktop

I'm hitting the same error, but with a twist — WSL is installed on my machine, but only because Docker Desktop uses it as its backend. There are no Linux distros with a real bash shell:

$ wsl --list --verbose
  NAME                STATE    VERSION
* docker-desktop      Running  2

What happens

Claude Code 2.1.42 auto-prepends bash to .sh hook commands on Windows. The system bash resolves to C:\Windows\System32\bash.exe (WSL shim), which intercepts the call. Since the docker-desktop WSL distro has no /bin/bash, it fails:

WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory

Debug log shows:

Hook output does not start with {, treating as plain text
Hook SessionStart:startup (SessionStart) error:
<3>WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory

The WSL error message pollutes stdout before the JSON output, so Claude Code can't parse the hook response.

Environment

  • Windows 11 (MSYS_NT-10.0-26200)
  • Claude Code v2.1.42
  • Superpowers v4.3.0
  • Git Bash installed at C:\Program Files\Git\bin\bash.exe
  • WSL 2 with docker-desktop distro only
  • Shell: MSYS2/Git Bash

Key difference from the original report

Git Bash is available — just not at the path WSL intercepts. The where bash output:

C:\Program Files\Git\usr\bin\bash.exe    ← Git Bash (works)
C:\Windows\System32\bash.exe             ← WSL shim (broken)

My workaround

Created a .cmd wrapper that explicitly calls Git Bash:

hooks/session-start.cmd:

@echo off
"C:\Program Files\Git\bin\bash.exe" "%~dp0session-start.sh"

hooks/hooks.json — changed command from .sh to .cmd:

"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd"

This works because Claude Code doesn't prepend bash to .cmd files.

+1 for the Node.js solution

The Node.js approach suggested in the original issue is the best long-term fix — it avoids all bash/WSL/path issues on Windows since Node.js is guaranteed to be available.

## Same issue, slightly different scenario: WSL installed for Docker Desktop I'm hitting the same error, but with a twist — WSL **is** installed on my machine, but only because **Docker Desktop** uses it as its backend. There are no Linux distros with a real bash shell: ``` $ wsl --list --verbose NAME STATE VERSION * docker-desktop Running 2 ``` ### What happens Claude Code 2.1.42 auto-prepends `bash` to `.sh` hook commands on Windows. The system `bash` resolves to `C:\Windows\System32\bash.exe` (WSL shim), which intercepts the call. Since the docker-desktop WSL distro has no `/bin/bash`, it fails: ``` WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory ``` Debug log shows: ``` Hook output does not start with {, treating as plain text Hook SessionStart:startup (SessionStart) error: <3>WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory ``` The WSL error message pollutes stdout before the JSON output, so Claude Code can't parse the hook response. ### Environment - Windows 11 (MSYS_NT-10.0-26200) - Claude Code v2.1.42 - Superpowers v4.3.0 - Git Bash installed at `C:\Program Files\Git\bin\bash.exe` - WSL 2 with docker-desktop distro only - Shell: MSYS2/Git Bash ### Key difference from the original report Git Bash **is** available — just not at the path WSL intercepts. The `where bash` output: ``` C:\Program Files\Git\usr\bin\bash.exe ← Git Bash (works) C:\Windows\System32\bash.exe ← WSL shim (broken) ``` ### My workaround Created a `.cmd` wrapper that explicitly calls Git Bash: **`hooks/session-start.cmd`:** ```cmd @echo off "C:\Program Files\Git\bin\bash.exe" "%~dp0session-start.sh" ``` **`hooks/hooks.json`** — changed command from `.sh` to `.cmd`: ```json "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd" ``` This works because Claude Code doesn't prepend `bash` to `.cmd` files. ### +1 for the Node.js solution The Node.js approach suggested in the original issue is the best long-term fix — it avoids all bash/WSL/path issues on Windows since Node.js is guaranteed to be available.
riperok commented 2026-02-13 23:56:52 +00:00 (Migrated from github.com)

Same issue, slightly different scenario: WSL installed for Docker Desktop

I'm hitting the same error, but with a twist — WSL is installed on my machine, but only because Docker Desktop uses it as its backend. There are no Linux distros with a real bash shell:

$ wsl --list --verbose
  NAME                STATE    VERSION
* docker-desktop      Running  2

What happens

Claude Code 2.1.42 auto-prepends bash to .sh hook commands on Windows. The system bash resolves to C:\Windows\System32\bash.exe (WSL shim), which intercepts the call. Since the docker-desktop WSL distro has no /bin/bash, it fails:

WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory

Debug log shows:

Hook output does not start with {, treating as plain text
Hook SessionStart:startup (SessionStart) error:
<3>WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory

The WSL error message pollutes stdout before the JSON output, so Claude Code can't parse the hook response.

Environment

  • Windows 11 (MSYS_NT-10.0-26200)
  • Claude Code v2.1.42
  • Superpowers v4.3.0
  • Git Bash installed at C:\Program Files\Git\bin\bash.exe
  • WSL 2 with docker-desktop distro only
  • Shell: MSYS2/Git Bash

Key difference from the original report

Git Bash is available — just not at the path WSL intercepts. The where bash output:

C:\Program Files\Git\usr\bin\bash.exe    ← Git Bash (works)
C:\Windows\System32\bash.exe             ← WSL shim (broken)

My workaround

Created a .cmd wrapper that explicitly calls Git Bash:

hooks/session-start.cmd:

@echo off
"C:\Program Files\Git\bin\bash.exe" "%~dp0session-start.sh"

hooks/hooks.json — changed command from .sh to .cmd:

"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd"

This works because Claude Code doesn't prepend bash to .cmd files.

+1 for the Node.js solution

The Node.js approach suggested in the original issue is the best long-term fix — it avoids all bash/WSL/path issues on Windows since Node.js is guaranteed to be available.

## Same issue, slightly different scenario: WSL installed for Docker Desktop I'm hitting the same error, but with a twist — WSL **is** installed on my machine, but only because **Docker Desktop** uses it as its backend. There are no Linux distros with a real bash shell: ``` $ wsl --list --verbose NAME STATE VERSION * docker-desktop Running 2 ``` ### What happens Claude Code 2.1.42 auto-prepends `bash` to `.sh` hook commands on Windows. The system `bash` resolves to `C:\Windows\System32\bash.exe` (WSL shim), which intercepts the call. Since the docker-desktop WSL distro has no `/bin/bash`, it fails: ``` WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory ``` Debug log shows: ``` Hook output does not start with {, treating as plain text Hook SessionStart:startup (SessionStart) error: <3>WSL (19290 - Relay) ERROR: CreateProcessCommon:800: execvpe(/bin/bash) failed: No such file or directory ``` The WSL error message pollutes stdout before the JSON output, so Claude Code can't parse the hook response. ### Environment - Windows 11 (MSYS_NT-10.0-26200) - Claude Code v2.1.42 - Superpowers v4.3.0 - Git Bash installed at `C:\Program Files\Git\bin\bash.exe` - WSL 2 with docker-desktop distro only - Shell: MSYS2/Git Bash ### Key difference from the original report Git Bash **is** available — just not at the path WSL intercepts. The `where bash` output: ``` C:\Program Files\Git\usr\bin\bash.exe ← Git Bash (works) C:\Windows\System32\bash.exe ← WSL shim (broken) ``` ### My workaround Created a `.cmd` wrapper that explicitly calls Git Bash: **`hooks/session-start.cmd`:** ```cmd @echo off "C:\Program Files\Git\bin\bash.exe" "%~dp0session-start.sh" ``` **`hooks/hooks.json`** — changed command from `.sh` to `.cmd`: ```json "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd" ``` This works because Claude Code doesn't prepend `bash` to `.cmd` files. ### +1 for the Node.js solution The Node.js approach suggested in the original issue is the best long-term fix — it avoids all bash/WSL/path issues on Windows since Node.js is guaranteed to be available.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
skills/obra-superpowers#440
No description provided.