settings.local.json fragility: multi-line bash commands corrupt permissions array

Resolved 💬 3 comments Opened Feb 8, 2026 by hyperpolymath Closed Feb 12, 2026

Summary

When users approve complex bash commands (especially heredocs, multi-line shell scripts, or commands with nested parentheses), Claude Code splits them into individual entries in settings.local.json's permissions.allow array. This creates entries with mismatched parentheses that fail Claude Code's own validation, causing the entire settings file to be skipped at startup.

Steps to Reproduce

  1. During a session, approve a bash command containing a heredoc, e.g.:

``bash
gh api repos/owner/repo/branches/main/protection -X PUT -H "Accept: application/vnd.github+json" --input - <<'JSON'
{
"required_pull_request_reviews": {
"dismiss_stale_reviews": true
}
}
JSON
``

  1. Claude Code auto-saves this as multiple separate permission entries:

``json
"Bash(1 <<'JSON'",
"{",
" \"required_pull_request_reviews\": {",
...
"JSON)"
``

  1. On next startup, the parenthesis validator rejects "Bash(1 <<'JSON'" (unmatched opening paren) and "JSON)" (unmatched closing paren)
  2. The entire settings.local.json is skipped, losing ALL permissions

Actual Results

Settings Error

 /var/home/hyper/.claude/settings.local.json
  └ permissions
    └ allow
      ├ "Bash(1 <<'JSON'": Mismatched parentheses
      └ "JSON)": Mismatched parentheses

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

User loses all 1000+ permission patterns because of 2 bad entries.

Expected Results

At minimum:

  • Skip only invalid entries, not the entire file
  • Ideally, don't split multi-line commands into separate array entries in the first place

Additional Context

This is a recurring issue. Other patterns that leak into the permissions array include:

  • Markdown text from GitHub issue bodies (## Summary, **System:**, etc.)
  • Shell control flow fragments (then, else, fi, done)
  • Heredoc delimiters (EOF), <<'EOF')
  • Bug report prose that happened to be in a bash command's arguments

Over time, the permissions array grows to 1000+ entries, many of which are invalid non-permission junk. A single bad entry with mismatched parens makes the entire file unusable.

Suggested Improvements

  1. Skip individual bad entries instead of rejecting the whole file
  2. Validate entries before persisting - check parenthesis balance before writing
  3. Don't split multi-line commands - store the full command as one entry, or use a hash/pattern rather than the literal command text
  4. Periodic self-cleanup - prune entries that are clearly not valid permission patterns

Workaround

I wrote a jq-based cleanup script that runs at boot and shell startup to catch and remove invalid entries before Claude Code sees them. Happy to share if useful.

Environment

  • Claude Code v2.1.37
  • Fedora Kinoite 43 (Linux 6.18.8)
  • Bash shell
  • Power user with 500+ repos (permissions list grows rapidly)

View original on GitHub ↗

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