[Bug] Project settings.local.json overwrites global settings instead of deep merging

Resolved 💬 4 comments Opened Jan 20, 2026 by mvrckhckrhub Closed Feb 27, 2026

Bug Description

Bug: Project settings.local.json overwrites global settings instead of merging

Summary

When a project-level .claude/settings.local.json exists, it appears to completely replace the global ~/.claude/settings.local.json rather than performing a deep merge. This causes global settings (like statusLine) to be ignored even when they're not defined in the project file.

Expected Behavior

Project settings should deeply merge with global settings, with project values taking precedence only for keys that are explicitly defined. Keys not present in the project file should fall back to global values.

Actual Behavior

The entire global config appears to be discarded when a project-level config exists.

Steps to Reproduce

  1. Create global settings at ~/.claude/settings.local.json:
{
  "includeCoAuthoredBy": false,
  "env": {
    "ENABLE_TOOL_SEARCH": "auto"
  },
  "permissions": {
    "allow": [
      "WebSearch",
      "WebFetch(domain:github.com)"
    ]
  },
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}
  1. Create project settings at <project>/.claude/settings.local.json:
{
  "permissions": {
    "allow": [
      "Bash(git init:*)"
    ]
  }
}
  1. Open Claude Code in the project directory
  2. Observe: statusLine does not appear
  1. Remove the project-level settings file
  2. Observe: statusLine now works

Workaround

Duplicating statusLine (and other global keys) into every project settings file works, but defeats the purpose of having global defaults.

Expected Merge Behavior

The effective config should be:

{
  "includeCoAuthoredBy": false,
  "env": {
    "ENABLE_TOOL_SEARCH": "auto"
  },
  "permissions": {
    "allow": [
      "Bash(git init:*)"
    ]
  },
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}

(Note: permissions.allow could either merge arrays or replace — either is reasonable as long as it's documented. But top-level keys like statusLine should definitely merge.)

Environment Info

  • Platform: darwin
  • Terminal: ghostty
  • Version: 2.1.12
  • Feedback ID: 5766bc7c-7ea8-491b-ac91-b4aded71ed34

Errors

[{"error":"Error: Plugin MCP server error - mcp-config-invalid: MCP server github invalid: Missing environment variables: GITHUB_PERSONAL_ACCESS_TOKEN\n    at WIT (/$bunfs/root/claude:4566:22181)\n    at async <anonymous> (/$bunfs/root/claude:5462:717)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:01.281Z"},{"error":"Error: NON-FATAL: Lock acquisition failed for /Users/haimschlesinger/.local/share/claude/versions/2.1.12 (expected in multi-process scenarios)\n    at HZR (/$bunfs/root/claude:3279:2091)\n    at aYA (/$bunfs/root/claude:3279:1202)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:01.315Z"},{"error":"Error: LSP server plugin:typescript-lsp:typescript failed to start: Executable not found in $PATH: \"typescript-language-server\"\n    at start (/$bunfs/root/claude:1564:22300)\n    at async $ (/$bunfs/root/claude:1564:24752)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:01.350Z"},{"error":"Error: Executable not found in $PATH: \"typescript-language-server\"\n    at spawn (unknown)\n    at spawn (node:child_process:667:35)\n    at spawn (node:child_process:14:39)\n    at start (/$bunfs/root/claude:1564:20845)\n    at start (/$bunfs/root/claude:1564:22354)\n    at $ (/$bunfs/root/claude:1564:24752)\n    at $ (/$bunfs/root/claude:1564:25727)\n    at _ (/$bunfs/root/claude:1564:32514)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:01.351Z"},{"error":"Error: Failed to start LSP server plugin:typescript-lsp:typescript: Executable not found in $PATH: \"typescript-language-server\"\n    at <anonymous> (/$bunfs/root/claude:1564:32536)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:01.351Z"},{"error":"Error: Plugin MCP server error - mcp-config-invalid: MCP server github invalid: Missing environment variables: GITHUB_PERSONAL_ACCESS_TOKEN\n    at WIT (/$bunfs/root/claude:4566:22181)\n    at async W (/$bunfs/root/claude:3527:13598)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:02.789Z"},{"error":"Error: Plugin MCP server error - mcp-config-invalid: MCP server github invalid: Missing environment variables: GITHUB_PERSONAL_ACCESS_TOKEN\n    at WIT (/$bunfs/root/claude:4566:22181)\n    at async J (/$bunfs/root/claude:3527:14114)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-01-20T11:25:02.789Z"}]

View original on GitHub ↗

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