[BUG] Auto-memory instructions direct an immediate MEMORY.md pointer edit, but the read-before-write gate deterministically rejects it

Status Open
Reported on v2.1.197
Maintainer reply None cached
Activity 0 comments · opened Jul 17, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The auto-memory system prompt and the Edit/Write read-before-write gate contradict each other, producing a deterministic error on the first memory save of essentially every session that saves one.

The memory instructions (a) inject MEMORY.md's full content into context every session, and (b) direct: "After writing the file, add a one-line pointer in MEMORY.md". The model follows them — saves the memory file, then immediately Edits MEMORY.md. The gate rejects with File has not been read yet. Read it first before writing to it, because no in-conversation Read of MEMORY.md has occurred (on a first save, none could reasonably have occurred — the file's content is already in the system prompt verbatim, so an explicit Read is redundant).

The recovery is always the same wasted loop: error → Read (a file already in context) → retry Edit → success. Several transcripts show 2–3 consecutive Reads during recovery. Measured over 14 days of local transcripts for one project (152 sessions): 106 File has not been read yet errors total, on every single day of the window, across client versions 2.1.197 → 2.1.209; the MEMORY.md-pointer flow is the reproducible core.

What Should Happen?

Any one of these resolves the contradiction:

  1. Files whose content the harness itself injects into context (MEMORY.md, and arguably CLAUDE.md) count as read-satisfied for the Edit/Write gate.
  2. The memory instructions say to Read MEMORY.md before adding the pointer line (documents the extra round-trip instead of guaranteeing an error).
  3. Edit validates by content match (unique old_string found ⇒ proceed) instead of requiring a prior Read — some current build already appears to behave this way (see Additional Information).

Error Messages/Logs

Representative sequence extracted from a session transcript (timestamps, tool, target):

05:46:18 Write memory/project_q282_scheduling_passthrough.md -> ok
05:46:26 Edit memory/MEMORY.md -> ERR <tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>
05:46:30 Read memory/MEMORY.md
05:46:36 Edit memory/MEMORY.md -> ok

Seven further sessions in the same 14-day window show the identical Write/Edit-memory-file → Edit-MEMORY.md → error → Read → retry shape.

Steps to Reproduce

  1. Use a project where auto-memory is active and MEMORY.md already exists with content (so its content is injected into the session context under "# Memory").
  2. Ask Claude to remember something durable (e.g. "remember that we use X convention"), such that it writes a new memory file per its instructions.
  3. Observe the next tool call: an Edit (or Write) to MEMORY.md adding the index pointer line, without a prior in-conversation Read — the model already has the file's content in context.
  4. The call fails with File has not been read yet. Read it first before writing to it.; the model then Reads and retries successfully.

The failure requires the model to follow the instructions literally (skip the redundant Read); across two weeks of sessions this occurred at least 9 times on MEMORY.md alone, so it is the common path, not an outlier.

Claude Model

Not sure / Multiple models

Is this a regression?

No, this never worked

Last Working Version

_N/A_

Claude Code Version

Observed across 2.1.197, 2.1.202, 2.1.205, 2.1.209 (per transcript version fields over the 14-day window)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

  • Enforcement appears inconsistent across builds/models: in a current session (Fable 5, same day the errors above were still occurring in parallel 2.1.209 sessions), Edit on a pre-existing never-Read file succeeded — the gate ran the old_string uniqueness check and applied the edit with no "has not been read" rejection — even though the session's own Edit/Write tool descriptions still document the rule as "the call will fail". So docs, instructions, and enforcement currently disagree in both directions depending on build.
  • Related but distinct open issues (different triggers for the same gate): #73281 (truncated whole-file Read doesn't satisfy the gate — a Read did happen) and #76361 (read-state resets on branch switch/compaction/parallel sessions). This report is specifically about the auto-memory instructions directing an edit that the gate is guaranteed to reject on first save.

View original on GitHub ↗