[BUG] [DEP0190] Startup hook with complex shell command triggers Node.js deprecation warning on every SessionStart
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
On Windows with Node.js v24.15.0, Claude Code outputs a DEP0190
deprecation warning every time a hook with type: "command" is executed.
The warning reads:
[DEP0190] DeprecationWarning: Passing args to a child process with a
shell option can lead to security vulnerabilities. Pass the shell
command as a string instead.
This happens during SessionStart hooks, but likely affects all hook
types (PostToolUse, Stop, etc.) that run shell commands.
ROOT CAUSE ANALYSIS:
The Claude Code hooks engine internally calls Node.js
child_process.spawn() with BOTH an args array AND {shell: true}
option simultaneously. Node.js v22+ deprecates this pattern because
when args are passed as an array with shell:true, the array elements
are concatenated into a single string without proper shell escaping,
which can lead to command injection vulnerabilities.
The offending call pattern is likely something like:
spawn(shellPath, ['-c', commandString], {shell: true})
or:
spawn(command, args, {shell: true})
Per Node.js docs, the correct pattern when using shell:true is to
pass the entire command as a single string (not an array):
spawn(commandString, {shell: true})
TROUBLESHOOTING DONE:
- Initially suspected the user's hook command complexity (nested
$() and escaped quotes) was the trigger — simplified to pure echo
commands, but the warning persisted intermittently.
- Verified it's NOT a user settings.json issue — the warning
originates from within Claude Code's internal hook execution
engine, not from user-provided shell or command configurations.
- Confirmed PowerShell 5.1 → 7+ upgrade would NOT fix it, as the
root cause is at the Node.js child_process API call layer, not
the external shell.
- Also reproduced in the claude-mem community plugin's
bun-runner.js, which had the same spawn(args, {shell:true})
anti-pattern. Fixed there by platform-detecting: on Windows, pass
command as string; on Unix, use array without shell:true.
WORKAROUNDS FOUND:
- Removing any explicit "shell" field from hook configurations in
settings.json reduces the frequency but does not eliminate the
warning entirely (Claude Code's internal shell invocation still
triggers it).
- The only complete user-side workaround is to avoid type: "command"
hooks entirely, which is not practical.
What Should Happen?
Claude Code should execute hook commands without triggering Node.js
deprecation warnings.
When a hook with type: "command" is configured, Claude Code's
internal hook runner should:
Option A (Recommended):
Detect whether shell:true is needed and use the correct spawn
signature:
- With shell:true → spawn(fullCommandString, {shell: true})
- Without shell → spawn(command, args)
Option B:
On Windows, when the target is already a shell (cmd.exe /
bash.exe), invoke it directly without the shell:true flag:
spawn('C:\\Windows\\System32\\cmd.exe', ['/c', command])
instead of:
spawn('C:\\Windows\\System32\\cmd.exe', ['/c', command],
{shell: true})
Either approach would eliminate the DEP0190 warning and align with
Node.js best practices for child process security.
Error Messages/Logs
Steps to Reproduce
- On Windows 11 with Node.js v24.15.0, install Claude Code 2.1.139
- Configure a SessionStart hook in ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [{
"matcher": "startup",
"hooks": [{
"type": "command",
"command": "echo 'test hook running'"
}]
}]
}
}
- Restart Claude Code (close and reopen the terminal, or run
claude in a new window)
- Observe the terminal output — the DEP0190 deprecation warning
appears during the SessionStart hook execution
- Also reproducible with any hook type that executes shell
commands (PostToolUse, Stop, etc.)
EXPECTED: Clean startup, no deprecation warnings
ACTUAL: [DEP0190] DeprecationWarning line appears in output
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.139
Claude Code Version
2.1.139
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
- This is a regression/issue exposed by Node.js v24's stricter
deprecation handling. Users on Node.js v20 or earlier may not
see this warning, but the underlying security concern exists in
all versions.
- The same anti-pattern was found and fixed in the claude-mem
community plugin's bun-runner.js and worker-service.cjs files,
serving as a reference for the required change pattern:
- Before: spawnSync('bun', ['run', script], {shell: true})
- After (Windows): spawnSync('bun run script', {shell: true})
- After (Unix): spawnSync('bun', ['run', script])
- This is particularly noticeable on Windows because the spawn
chain is longer: Claude Code → bash.exe → cmd.exe → target
command, and each layer can trigger individual warnings.
- Related Node.js docs:
https://nodejs.org/api/child_process.html#child_processspawncommand-args-options
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗