claude-code - 💡(How to fix) Fix [BUG] [DEP0190] Startup hook with complex shell command triggers Node.js deprecation warning on every SessionStart

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

Error Messages/Logs

Root Cause

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.

Fix Action

Fix / Workaround

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.
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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

  1. On Windows 11 with Node.js v24.15.0, install Claude Code 2.1.139

  2. Configure a SessionStart hook in ~/.claude/settings.json: { "hooks": { "SessionStart": [{ "matcher": "startup", "hooks": [{ "type": "command", "command": "echo 'test hook running'" }] }] } }

  3. Restart Claude Code (close and reopen the terminal, or run claude in a new window)

  4. Observe the terminal output — the DEP0190 deprecation warning appears during the SessionStart hook execution

  5. 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

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] [DEP0190] Startup hook with complex shell command triggers Node.js deprecation warning on every SessionStart