Permission learning saves invalid command fragments to settings.local.json
Status Closed — duplicate
Maintainer reply None cached
Activity 3 comments · opened Jan 7, 2026 · 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 ↗