Invalid entries written to settings.local.json when allowing Bash commands

Resolved 💬 3 comments Opened Jan 5, 2026 by warusaku Closed Jan 8, 2026

Description

Claude Code CLI writes invalid entries to settings.local.json when users allow certain Bash commands, causing the entire settings file to be skipped with the error "Files with errors are skipped entirely."

Problem Cases

1. Shell parameter expansion fragments saved as separate entries

When a command containing shell parameter expansion like ${var%%pattern} or ${var##pattern} is allowed, fragments are incorrectly saved as separate entries:

Original command (in a for loop):

for device in "192.168.1.1:device1"; do
  name="${device%%:*}"
  ip="${device##*:}"
done

Incorrectly saved as:

"Bash(name=\"$device%%:*\")",
"Bash(ip=\"$device##*:\")"

These are not valid Bash commands and cause parser errors.

2. Regex patterns with .* cause parser confusion

Commands containing regex .* are saved as-is:

"Bash(... grep -E 'pattern.*here' ...)"

The parser then incorrectly interprets * as a wildcard pattern (expecting :* format) and reports:

"Use :* for prefix matching, not just *"

Impact

  • Settings file becomes invalid and is skipped entirely
  • Invalid entries accumulate over time as more commands are allowed
  • Users must manually clean up the settings file

Expected Behavior

  1. Validate entries before writing to settings.local.json
  2. Reject or escape entries containing problematic patterns (%%, ##, standalone *)
  3. Or: properly parse shell syntax to avoid fragmenting commands

Environment

  • Claude Code CLI (latest)
  • macOS

Workaround

Manually remove invalid entries from .claude/settings.local.json using:

import json, re
with open('.claude/settings.local.json', 'r') as f:
    data = json.load(f)
data['permissions']['allow'] = [
    item for item in data['permissions']['allow']
    if not re.search(r'(?<![:])\*|%%|##', item)
]
with open('.claude/settings.local.json', 'w') as f:
    json.dump(data, f, indent=2)

View original on GitHub ↗

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