[BUG] Claude Code generates malformed permission patterns in settings.local.json, causing validation errors and possible terminal crashes

Resolved 💬 3 comments Opened Dec 31, 2025 by Yi-Yi-y Closed Jan 3, 2026

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?

Claude Code is automatically generating incorrectly-formatted permission patterns when saving bash
command permissions to settings.local.json. The patterns use instead of : for prefix matching, causing validation errors on every startup. Additionally, the terminal crashes intermittently, particularly when certain commands (WebFetch, file operations) are executed, which may be related to the settings validation failing.

What Should Happen?

  • Permission patterns should use : for prefix matching: "Bash(Speaker:)"
  • Complex piped commands should be saved as single permission entries
  • Settings should validate successfully
  • Terminal should not crash

Error Messages/Logs

Example Malformed Entries

  "Bash(Speaker*)",
  "Bash(Transcript*)",
  "Bash(Audio*)",
  "Bash(powershell -Command \"Get-Process | Where-Object {$_ProcessName -like ''*whisper*''} | Select-Object ProcessName, Id, Path\")",
  "Bash(Where-Object {$_DisplayName -like \"*audio*\" -or $_Name -like \"*audio*\"})",
  "Bash(Format-Table -AutoSize Name, DisplayName, Status, StartType)"


Settings Error

 C:\Users\Robean\.claude\settings.local.json
  └ permissions
    └ allow
      ├ "Bash(Speaker*)": Use ":*" for prefix matching, not just "*". Change to "Bash(Speaker:*)"    
  for prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(Transcript*)": Use ":*" for prefix matching, not just "*". Change to 
  "Bash(Transcript:*)" for prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(Audio*)": Use ":*" for prefix matching, not just "*". Change to "Bash(Audio:*)" for    
  prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(powershell -Command "Get-Process | Where-Object {$_ProcessName -like ''*whisper*''} |  
  Select-Object ProcessName, Id, Path")": Use ":*" for prefix matching, not just "*". Change to      
  "Bash(powershell -Command "Get-Process | Where-Object {$_ProcessName -like '':*whisper:*''} |      
  Select-Object ProcessName, Id, Path")" for prefix matching. Examples: Bash(npm run:*), Bash(git:*) 
      ├ "Bash(Where-Object {$_DisplayName -like "*audio*" -or $_Name -like "*audio*"})": Use ":*"    
  for prefix matching, not just "*". Change to "Bash(Where-Object {$_DisplayName -like ":*audio:*"   
  -or $_Name -like ":*audio:*"})" for prefix matching. Examples: Bash(npm run:*), Bash(git:*)        
      └ "Bash(powershell
        ├ exe -Command "Get-Service | Where-Object {$_
───────────────────────────────────────────────────────────────────────────────────────────────────── Settings Error

 C:\Users\Robean\.claude\settings.local.json
  └ permissions
    └ allow
      ├ "Bash(Speaker*)": Use ":*" for prefix matching, not just "*". Change to "Bash(Speaker:*)"    
  for prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(Transcript*)": Use ":*" for prefix matching, not just "*". Change to 
  "Bash(Transcript:*)" for prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(Audio*)": Use ":*" for prefix matching, not just "*". Change to "Bash(Audio:*)" for    
  prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(powershell -Command "Get-Process | Where-Object {$_ProcessName -like ''*whisper*''} |  
  Select-Object ProcessName, Id, Path")": Use ":*" for prefix matching, not just "*". Change to      
  "Bash(powershell -Command "Get-Process | Where-Object {$_ProcessName -like '':*whisper:*''} |      
  Select-Object ProcessName, Id, Path")" for prefix matching. Examples: Bash(npm run:*), Bash(git:*) 
      ├ "Bash(Where-Object {$_DisplayName -like "*audio*" -or $_Name -like "*audio*"})": Use ":*"    
  for prefix matching, not just "*". Change to "Bash(Where-Object {$_DisplayName -like ":*audio:*"   
  -or $_Name -like ":*audio:*"})" for prefix matching. Examples: Bash(npm run:*), Bash(git:*)        
      └ "Bash(powershell
───────────────────────────────────────────────────────────────────────────────────────────────────── Settings Error

 C:\Users\Robean\.claude\settings.local.json
  └ permissions
    └ allow
      ├ "Bash(Speaker*)": Use ":*" for prefix matching, not just "*". Change to "Bash(Speaker:*)"    
  for prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(Transcript*)": Use ":*" for prefix matching, not just "*". Change to 
  "Bash(Transcript:*)" for prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(Audio*)": Use ":*" for prefix matching, not just "*". Change to "Bash(Audio:*)" for    
  prefix matching. Examples: Bash(npm run:*), Bash(git:*)
      ├ "Bash(powershell -Command "Get-Process | Where-Object {$_ProcessName -like ''*whisper*''} |  
  Select-Object ProcessName, Id, Path")": Use ":*" for prefix matching, not just "*". Change to      
  "Bash(powershell -Command "Get-Process | Where-Object {$_ProcessName -like '':*whisper:*''} |      
  Select-Object ProcessName, Id, Path")" for prefix matching. Examples: Bash(npm run:*), Bash(git:*) 
      ├ "Bash(Where-Object {$_DisplayName -like "*audio*" -or $_Name -like "*audio*"})": Use ":*"    
  for prefix matching, not just "*". Change to "Bash(Where-Object {$_DisplayName -like ":*audio:*"   
  -or $_Name -like ":*audio:*"})" for prefix matching. Examples: Bash(npm run:*), Bash(git:*)        
      └ "Bash(powershell
        ├ exe -Command "Get-Service | Where-Object {$_
        │ └ DisplayName -like ''*audio*'' -or $_
        │   └ Name -like ''*audio*''} | Format-Table -AutoSize Name, DisplayName, Status, 
  StartType")": Use ":*" for prefix matching, not just "*". Change to "Bash(powershell.exe -Command  
  "Get-Service | Where-Object {$_.DisplayName -like '':*audio:*'' -or $_.Name -like '':*audio:*''} | 
   Format-Table -AutoSize Name, DisplayName, Status, StartType")" for prefix matching. Examples:     
  Bash(npm run:*), Bash(git:*)
        └ exe -Command "Get-CimInstance Win32_PnPSignedDriver | Where-Object {$_DeviceClass -eq      
  ''MEDIA'' -or $_DeviceName -like ''*audio*''} | Select-Object 
  DeviceName,DriverVersion,DriverDate,Manufacturer | Format-List")": Use ":*" for prefix matching,   
  not just "*". Change to "Bash(powershell.exe -Command "Get-CimInstance Win32_PnPSignedDriver |     
  Where-Object {$_DeviceClass -eq ''MEDIA'' -or $_DeviceName -like '':*audio:*''} | Select-Object    
  DeviceName,DriverVersion,DriverDate,Manufacturer | Format-List")" for prefix matching. Examples:   
  Bash(npm run:*), Bash(git:*)

 Files with errors are skipped entirely, not just the invalid settings.

Steps to Reproduce

  1. Use Claude Code and allow it to run bash commands (particularly PowerShell commands with wildcards or piped commands)
  2. When prompted for permission, approve and allow Claude Code to save the permission
  3. Check ~/.claude/settings.local.json - malformed patterns appear like:
  • "Bash(Speaker)" instead of "Bash(Speaker:)"
  • "Bash(Transcript)" instead of "Bash(Transcript:)"
  • Fragmented pipeline commands saved as separate entries
  1. Settings validation errors appear on startup
  2. Terminal crashes randomly, especially during WebFetch or certain tool operations

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.075.

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

Additional Context

  • User never manually edits settings file - all entries are auto-generated by Claude Code
  • Issue persists across multiple sessions
  • Malformed entries appear to be generated when Claude runs commands on user's behalf
  • PowerShell commands with wildcards inside (e.g., -like 'audio') seem particularly problematic
  • Terminal crashes are infrequent but correlate with certain command executions (WebFetch, file operations)

Impact

  • Settings validation errors on every startup
  • Cannot use wildcards for bash command permissions without manual editing
  • Potential terminal instability/crashes
  • User experience degradation

Even when the settings file has been validated again, and fixed by claude code, it returns within a few days.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗