[OPUS4.7] Read tool returns different content for ~/.claude/settings.json across calls within the same session — effective-view rendering or bug?
Preflight Checklist
- [x] I have searched existing issues for similar behavior reports
- [x] This report does NOT contain sensitive information (API keys, passwords, etc.)
Type of Behavior Issue
Claude modified files I didn't ask it to modify
What You Asked Claude to Do
I observed the following behavior in Claude Code v2.1.123 (Opus 4.7, 1M context, WSL on Windows):
Within a single Claude Code session, two Read tool calls against the same path (~/.claude/settings.json = /home/philc/.claude/settings.json) returned materially different content with no on-disk changes between them.
First Read (session-start, pre-flight verification): returned 131 lines including a permissions block with curated allow, ask, and deny arrays, defaultMode: "acceptEdits", and disableBypassPermissionsMode: "disable". The deny array contained Bash(curl:*) at line 109.
Subsequent Read (mid-session, root-cause investigation): returned 24 lines containing only enabledPlugins and statusLine. No permissions block at all.
Verified from a fresh WSL terminal (not from inside Claude Code):
On-disk file is 892 bytes, 24 lines, mtime Apr 29 18:42 — matches the second Read.
Pre-session backup (settings.json.bak.20260429T163945Z, mtime Apr 29 09:41) is also 892 bytes — disk has been the 24-line skeleton continuously since before the session opened.
CLAUDE_CONFIG_DIR is unset on both WSL and Windows sides.
Windows-side %USERPROFILE%\.claude\settings.json is a separate 23-line / 743-byte file with mtime 2026-04-10 (different content, different machine, three weeks stale; not the source of either Read).
Behavior consistent with the 24-line skeleton being the actual substrate: a curl https://example.com invocation prompted with the generic "This command requires approval" wording rather than refusing with "Permission to use Bash with command curl https://example.com/ has been denied" wording — i.e., defaultMode fallthrough rather than deny-rule firing.
Trying to determine which of the following is happening:
Claude Code renders an effective-config view at session-start (raw user config merged with built-in defaults) and the Read tool returned that view; subsequent Reads return raw on-disk bytes. If so, is there a documented way to inspect the effective view from inside a running session (e.g., a slash command, CLI flag, or canonical Read path)?
The Read tool returned cached or otherwise incorrect content at session-start. Tool-level bug.
Something else.
The answer affects how I draft permission-related briefs going forward — specifically, whether file-content audits of ~/.claude/settings.json can be trusted as a basis for permission-state reasoning, or whether substrate verification needs to drive through runtime behavior probes instead.
Happy to provide additional context (session ID, full transcripts of both Reads, the project-layer config that was active during the second Read) if useful.
What Claude Actually Did
Here's the "Actual behavior" field text:
Actual behavior:
Two Read tool calls against ~/.claude/settings.json within the same session returned materially different content despite no on-disk changes between them.
The first Read (early in the session) returned 131 lines including a full permissions block with curated allow, ask, and deny arrays (Bash(curl:*) was in the deny array at line 109), defaultMode: "acceptEdits", and disableBypassPermissionsMode: "disable".
A subsequent Read (later in the same session) of the same path returned only 24 lines containing enabledPlugins and statusLine — no permissions block at all.
Verified from a fresh WSL terminal outside Claude Code that the on-disk file is 892 bytes / 24 lines / mtime Apr 29 18:42, matching the second Read. The pre-session backup is also 892 bytes, confirming the file has been the 24-line skeleton continuously since before the session opened. The first Read returned content that does not correspond to the on-disk file at any point in the session window.
Runtime permission behavior matches the 24-line on-disk content rather than the 131-line first-Read content: a curl https://example.com attempt prompted with the generic "This command requires approval" wording rather than refusing with deny-rule wording, indicating the curated deny array seen in the first Read is not actually active at runtime.
Expected Behavior
Two Read tool calls against the same file path within a single session, with no on-disk changes between them, should return identical content. Either both should return the raw on-disk bytes (24 lines, the actual file content), or both should return an effective-config view if Claude Code renders one — but the behavior should be consistent across calls within a session.
If effective-config rendering is an intentional feature (raw user config merged with Claude Code's built-in defaults), this should be documented, and there should be a documented way to inspect the effective view from inside a running session.
Files Affected
Permission Mode
Accept Edits was ON (auto-accepting changes)
Can You Reproduce This?
Yes, every time with the same prompt
Steps to Reproduce
_No response_
Claude Model
Sonnet
Relevant Conversation
Impact
Critical - Data loss or corrupted project
Claude Code Version
Opus 4.7
Platform
Anthropic API
Additional Context
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗