Permission learning saves invalid command fragments to settings.local.json
Resolved 💬 3 comments Opened Jan 7, 2026 by noamrazbuilds Closed Jan 11, 2026
Bug Description
Claude Code's permission learning mechanism incorrectly saves fragments of complex shell commands as separate permission entries, resulting in a corrupted settings.local.json file that fails to load.
Expected Behavior
When a user approves a complex bash command (e.g., a git commit with heredoc, or a for-loop), the permission system should either:
- Save a valid generalized pattern (e.g.,
Bash(git commit:*)) - Skip saving commands that can't be represented as valid patterns
- Properly escape and store the complete command
Actual Behavior
Complex commands get fragmented and saved as individual invalid entries. For example:
A for-loop gets split into:
"Bash(for fn in formatTierName formatTrialStatus ...)",
"Bash(do echo -n \"$fn: \")",
"Bash(done)",
File paths saved as Bash commands:
"Bash(CLAUDE.md )",
"Bash(gentlr/app.js )",
Git commits with heredocs saved with malformed escaping:
"Bash(git -C /path commit -m \"$\\(cat <<''EOF''\n...commit message...\\)\")"
Impact
- Claude Code fails to start with settings parsing errors
- Users cannot use the project until they manually fix or delete the settings file
- Loss of legitimate permission settings mixed in with corrupted ones
Steps to Reproduce
- Start Claude Code in a project
- Run complex bash commands that include:
- Multi-line for-loops
- Git commits with heredoc message syntax
- Commands with special shell characters
- Approve these commands when prompted
- Check
.claude/settings.local.json- it will contain fragmented/invalid entries - Restart Claude Code - it fails to load settings
Environment
- Claude Code CLI
- macOS (Darwin 25.2.0)
- Model: Claude Opus 4.5
Suggested Fix
The permission saving logic should:
- Validate that saved patterns are syntactically correct before writing
- For complex commands, extract just the base command (e.g.,
git commit) rather than the full invocation - Reject/skip entries that contain shell control structures (for/do/done, if/then/fi, heredocs)
- Never save raw file paths as Bash commands
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗