Skip to content

fix(windows): use absolute path with shell:false for Claude spawn#143

Merged
tiann merged 1 commit intotiann:mainfrom
tw23:fix/windows-claude-spawn
Feb 3, 2026
Merged

fix(windows): use absolute path with shell:false for Claude spawn#143
tiann merged 1 commit intotiann:mainfrom
tw23:fix/windows-claude-spawn

Conversation

@tw23
Copy link
Contributor

@tw23 tw23 commented Feb 2, 2026

On Windows, spawning Claude with shell: true causes the process to exit immediately with code 1. This happens because shell: true invokes cmd.exe /c claude , and cmd.exe's PATH resolution differs from direct process creation, leading to environment inconsistencies.

This fix:

  • Adds findWindowsClaudePath() to locate claude.exe absolute path
  • Changes spawn to use absolute path with shell: false on Windows
  • Maintains Unix behavior (command name works fine with shell: false)
  • Adds HAPI_CLAUDE_PATH env var for user override

Tested on Windows 11 with Claude Code v2.1.29 and hapi v0.15.0.

On Windows, spawning Claude with shell: true causes the process to
exit immediately with code 1. This happens because shell: true invokes
cmd.exe /c claude <args>, and cmd.exe's PATH resolution differs from
direct process creation, leading to environment inconsistencies.

This fix:
- Adds findWindowsClaudePath() to locate claude.exe absolute path
- Changes spawn to use absolute path with shell: false on Windows
- Maintains Unix behavior (command name works fine with shell: false)
- Adds HAPI_CLAUDE_PATH env var for user override

Tested on Windows 11 with Claude Code v2.1.29 and hapi v0.15.0.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
logger.debug(`[ClaudeLocal] Spawning claude with args: ${JSON.stringify(args)}`);

// Get Claude executable path (absolute path on Windows for shell: false)
const claudeCommand = getDefaultClaudeCodePath();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] [CLEANUP] MCP config cleanup can be skipped on early failure

Why this is a problem: getDefaultClaudeCodePath() can throw before the try/finally, so cleanupMcpConfig never runs. On Windows this can leave a mcp-config-*.json file with server config in the project dir.

Suggested fix:

try {
    const claudeCommand = getDefaultClaudeCodePath()
    logger.debug(`[ClaudeLocal] Using claude executable: ${claudeCommand}`)
    await spawnWithAbort({ command: claudeCommand, args, /* existing options */ })
} finally {
    cleanupMcpConfig?.()
    process.stdin.resume()
    restoreTerminalState()
}

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Minor] MCP config cleanup can be skipped if Claude path resolution fails before the try/finally in cli/src/claude/claudeLocal.ts:89. Suggested fix: move getDefaultClaudeCodePath() into the try block so cleanup always runs.

Testing

  • Not run (automation)

@tiann tiann merged commit 798317c into tiann:main Feb 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants