
Claude Code의 Edit이 '성공'했음에도 파일이 바뀌지 않는 현상 — 긴 세션에서 발생하는 침묵의 불일치와 그 탐지법
요약
Claude Code 사용 중 Edit 작업이 성공으로 보고됨에도 실제 파일이 변경되지 않는 현상의 원인과 해결책을 다룹니다. 이는 임시 디렉토리(TMPDIR)의 용량 부족(ENOSPC)으로 인해 발생하는 문제임을 밝히고 탐지 및 방지 방법을 제시합니다.
핵심 포인트
- Edit 성공 보고와 실제 파일 변경 간의 불일치 현상 원인 규명
- 근본 원인은 메인 디스크가 아닌 임시 영역(TMPDIR)의 용량 부족(ENOSPC)
- df 명령어를 통해 임시 영역의 여유 공간을 사전에 확인하는 방법
- CLAUDE_CODE_TMPDIR 환경 변수를 통한 임시 디렉토리 경로 변경 방법
Claude Code를 오래 실행하다 보면, 아주 드물게 이런 상황을 마주하게 된다.
Edit
이 '성공(success)'이라고 응답한다. 로그에도 success라고 뜬다. 그런데 파일을 열어보면 아무것도 변하지 않았다. 에이전트는 성공했다고 믿고 다음 단계로 넘어가며, 변하지 않은 파일을 전제로 작업을 계속해 나간다. 깨달았을 때는 이미 토대가 무너진 뒤다.
이것은 '수령증(성공이라는 보고)'과 '실제 효과(파일이 정말로 바뀌었는가)'가 어긋나는 현상이다. 최근 이 증상의 근본 원인이 명확해졌기에, 기제와 스스로 탐지하는 방법을 정리한다.
처음에는 '특수한 문자나 너무 긴 문자열 때문인가?'라고 의심하기 쉽다. 화살표나 체크 마크, 중첩된 markdown, 백틱(backtick) 같은 것들 말이다.
하지만 이것들은 원인이 아니다. 동일한 재료(길고 기호가 많은 new_string)를 짧고 평범한 세션에서 Edit에 적용해도 매번 제대로 반영된다. 다시 읽어와서 grep -c로 세어봐도 전부 들어있다.
즉, 변수는 '문자열의 내용'이 아니라 '세션의 상태' 쪽에 있다.
실제로 보고된 근본 원인은 이것이었다. 자식 프로세스(child process)가 임시 영역에 쓰려고 시도하다가 용량이 다 차서 실패하는 것(ENOSPC)이다. 그런데 도구(tool) 계층에서는 '성공'이라는 수령증을 반환해 버린다.
Command output was lost: the temp filesystem ... is full (0MB free).
The child process's stdout/stderr writes failed with ENOSPC.
이것 하나만으로 긴 세션에서 발생하는 여러 증상을 설명할 수 있다.
- Edit이 성공했다고 보고하지만 바뀌지 않음: 쓰기 작업이 ENOSPC로 실패했음에도 수령증은 성공으로 전달됨
- 한꺼번에 보낸 도구 호출이 사라짐: 작업 영역으로의 쓰기가 실패하여 결과가 빈 상태가 됨
- Bash 출력이 끊기거나 첫 줄만 실행됨: 표준 출력(stdout) 임시 영역으로의 쓰기가 실패
헷갈리는 점은 메인 디스크에는 여유 공간이 있다는 것이다 (내 환경에서는 109GB나 남아 있었다). 실패하고 있는 것은 메인 디스크가 아니라, 그 임시 영역의 작은 구획이다.
가장 무서운 것은 이것이 '침묵' 속에서 일어난다는 점이다. 에러로 멈춰준다면 알아챌 수 있다. 성공했다고 보고하며 진행되면 알아챌 수 없다. 그래서 진행하기 전에 여유 공간을 확인한다.
먼저, 실제로 사용되고 있는 임시 영역의 구획을 확인한다. 메인 디스크가 아니라 임시 영역 그 자체를 보는 것이 핵심이다.
df -h "${CLAUDE_CODE_TMPDIR:-$TMPDIR}"
이곳의 용량이 작거나 거의 100% 사용 중이라면 그것이 범인이다. 그리고 작업 전에 여유 공간이 부족하면 크게 경고하는 한 줄을 끼워 넣는다.
T="${CLAUDE_CODE_TMPDIR:-${TMPDIR:-/tmp}}"
avail=$(df -Pk "$T" | awk 'NR==2{print $4}')
[ "$avail" -lt 51200 ] && echo "WARN: 임시 영역의 여유 공간이 50MB 미만입니다. Edit/Bash의 성공 보고가 거짓일 수 있습니다" >&2
에러 메시지 자체가 제시하는 회피책도 효과적이다. 임시 영역을 용량에 여유가 있는 곳으로 옮긴다.
export CLAUDE_CODE_TMPDIR=/path/to/roomy/dir
하지만 회피보다 탐지가 더 중요하다. 회피는 용량을 늘릴 뿐이며, 다시 가득 차면 똑같은 일이 발생한다. 탐지는 가득 찬 순간 침묵이 아니라 큰 소리로 알려준다.
왜 임시 영역이 가득 차는지(병렬 태스크가 서로 경쟁하는지, 구획에 상한이 있는지)는 환경에 따라 다르다. 하지만 본질은 그 이유와는 독립적이다.
쓰기에 실패했다면 성공이라는 수령증을 반환해서는 안 된다. 성공했다고 보고되었는데 아무 일도 일어나지 않는, 이 침묵의 불일치가 가장 위험하다. 하류(downstream)의 모든 것이 일어나지 않은 수령증을 믿고 진행해 버리기 때문이다.
긴 세션에서 Edit의 동작이 수상하다고 느껴진다면, 먼저 임시 영역의 여유 공간을 의심하라. 그리고 수령증을 맹신하지 말고, 편집 후에 다시 읽어와서 확인하는 습관을 들여라.
이러한 종류의 '침묵의 데이터 소실'이나 토큰 폭주, 권한 사고를 송출 전에 막는 안전장치와 월간 점검 체크리스트를 무료로 제공하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기