Claude Code 빌드 오류 분류 루프: 15분 안에 원인 좁히기
Node와 Astro 빌드 실패를 로그 분류, 진단, 수정, 검증으로 나누어 Claude Code로 처리하는 절차입니다.
수정 전에 빌드 오류를 먼저 나누기
Node, Astro, Vite, Next.js 빌드가 실패하면 전체 로그를 Claude Code에 붙이고 한번에 고쳐 달라고 하기 쉽습니다. 하지만 전체 로그에는 첫 실패 줄, 뒤따라 나온 stack trace, package manager 출력, 불필요한 정리가 섞입니다. 빌드가 통과해도 원인 설명이 약하면 review에서 다시 멈춥니다.
이 글은 버그 리포트 템플릿, 리뷰 워크플로 체크리스트, 검증 레시트 워크플로를 빌드 실패에 적용한 절차입니다. 목표는 한번에 크게 고치는 것이 아니라, 15분 안에 원인 후보를 하나로 좁히고 최소 수정과 증거를 남기는 것입니다.
harness는 에이전트의 발판이라고 보면 됩니다. Claude Code가 코드를 읽고 추론하더라도, 어떤 로그를 볼지, 어떤 가설만 허용할지, 어떤 명령으로 증명할지는 사람이 먼저 정해야 합니다. 이 발판이 있어야 build fix 세션이 넓은 리팩터링으로 번지지 않습니다.
flowchart LR
A[State] --> B[Build log]
B --> C[First failing line]
C --> D[One hypothesis]
D --> E[Small fix]
E --> F[Proof command]
F --> G[Receipt]
15분 루프
15분을 5분씩 세 구간으로 나눕니다. 첫 5분은 증거 수집입니다. 파일을 수정하지 않고 git status, 실패한 build 명령, 첫 실패 줄, 관련 파일만 모읍니다. 다음 5분은 가설을 하나 고릅니다. dependency, import path, frontmatter, data shape, permission, network, test expectation 중 어디에 가까운지 결정합니다.
마지막 5분에서만 코드나 설정을 수정합니다. 수정 후에는 실패했던 명령뿐 아니라 관련 페이지와 CTA도 확인합니다. 콘텐츠 사이트에서는 green build가 충분한 증거가 아닙니다. h1, canonical, heroImage, product link, training link가 그대로 살아 있어야 공개 품질을 지킬 수 있습니다.
Masa의 작업 메모는 항상 세 줄입니다. 원인, 변경, 증거. reviewer는 긴 설명보다 왜 그 가설을 골랐는지, 무엇을 바꿨는지, 어떤 명령이나 URL로 확인했는지를 보고 싶어 합니다. Claude Code에도 마지막에 이 세 줄을 요구하면 다음 장애 대응의 시작점이 됩니다.
같은 순서로 증거 수집
매번 같은 순서로 명령을 실행합니다. macOS, Linux, WSL에서는 아래 shell 예제를 그대로 사용할 수 있습니다.
git status --short
npm run build 2>&1 | tee build.log
status=${PIPESTATUS[0]}
if [ "$status" -ne 0 ]; then
grep -Ein "error|failed|ERR_|Cannot|TypeError" build.log | head -n 20
exit "$status"
fi
npm test -- --runInBand
Windows PowerShell에서는 npm.cmd를 명시하는 편이 안전합니다. shell마다 npm 해석이 달라질 수 있기 때문입니다.
$ErrorActionPreference = "Continue"
git status --short
npm.cmd run build *> build.log
$buildExit = $LASTEXITCODE
if ($buildExit -ne 0) {
Select-String -Path build.log -Pattern "error|failed|ERR_|Cannot|TypeError" |
Select-Object -First 20
exit $buildExit
}
npm.cmd test -- --runInBand
첫 실행은 성공하지 않아도 됩니다. 목적은 가장 유용한 첫 실패를 저장하는 것입니다. 로그 마지막의 stack trace보다 처음 나온 error가 원인에 더 가까운 경우가 많습니다.
Node로 첫 실패를 분류하기
아래 스크립트를 scripts/triage-build-log.mjs로 저장하고 node scripts/triage-build-log.mjs build.log를 실행합니다. 코드를 고치지 않고, 큰 로그를 하나의 bucket과 다음 진단 방향으로 줄입니다.
#!/usr/bin/env node
import { readFileSync } from "node:fs";
const logPath = process.argv[2];
if (!logPath) {
console.error("Usage: node scripts/triage-build-log.mjs build.log");
process.exit(1);
}
const rules = [
{ name: "dependency or import path", regex: /Cannot find module|ERR_MODULE_NOT_FOUND|Cannot resolve/i },
{ name: "runtime null or shape mismatch", regex: /TypeError:.*undefined|undefined is not|Cannot read/i },
{ name: "test expectation drift", regex: /Expected.*received|AssertionError|Snapshot/i },
{ name: "permission or sandbox boundary", regex: /EACCES|EPERM|permission denied/i },
{ name: "Astro content or frontmatter", regex: /frontmatter|content collection|InvalidContentEntry|MDX/i },
];
const lines = readFileSync(logPath, "utf8").split(/\r?\n/);
const firstFailure = lines.find((line) => /error|failed|ERR_|Cannot|TypeError/i.test(line));
const matchedRule = rules.find((rule) => firstFailure && rule.regex.test(firstFailure));
console.log(JSON.stringify({
firstFailure: firstFailure || "No obvious failure line found",
bucket: matchedRule ? matchedRule.name : "needs manual reading",
nextDiagnostic: matchedRule
? "Run one command that proves or disproves this bucket before editing files."
: "Read the 30 lines before the first failure and classify manually.",
}, null, 2));
이 분류는 완벽할 필요가 없습니다. 중요한 것은 Claude Code에게 “build를 고쳐 줘”가 아니라 “이 bucket을 증명하거나 배제하는 최소 진단을 먼저 제시해 줘”라고 말할 수 있다는 점입니다.
공식 문서로 경계 정하기
Claude Code 자체의 연결, 인증, 사용량 제한, 런타임 메시지는 Claude Code Error reference를 봅니다. CLAUDE.md, settings, hooks, MCP가 로드되지 않는 것 같다면 Debug your configuration을 확인합니다.
Astro 콘텐츠 사이트의 frontmatter와 content collection 문제는 Astro Content Collections를 기준으로 봅니다. ERR_MODULE_NOT_FOUND 같은 Node 오류 코드는 Node.js Errors에서 확인합니다. 이 경계를 분리하면 Claude Code 문제와 애플리케이션 build 문제를 섞지 않을 수 있습니다.
오류 형태별 첫 동작
| 로그 형태 | 먼저 의심할 것 | 첫 동작 |
|---|---|---|
Cannot find module | import path, generated file, missing dependency | package 추가 전에 파일과 path 확인 |
ERR_MODULE_NOT_FOUND | ESM/CJS, extension, package exports | Node error와 package 설정 비교 |
undefined is not | data shape, frontmatter, API response | null check 전에 실제 데이터 1건 출력 |
Expected ... received | spec change, fixture, snapshot | 의도한 변경인지 regression인지 분류 |
permission denied | sandbox, CI user, write path | working directory와 권한 확인 |
Build failed만 있음 | 위쪽의 첫 error | 마지막 trace가 아니라 첫 error 추출 |
Astro 기사 사이트에서 undefined is not an object가 보이면 바로 null guard를 넣지 않습니다. 특정 locale의 heroImage, pubDate, lang이 빠졌을 수 있습니다. 넓은 방어 코드는 build를 통과시킬 수 있지만 품질 문제를 숨길 수 있습니다.
복사해서 쓰는 Claude Code 프롬프트
이 실패한 build log를 읽어 주세요.
넓은 리팩터링은 제안하지 마세요.
아직 파일을 편집하지 마세요.
반환할 내용:
1. 처음 실패한 줄
2. 가장 가능성 높은 원인 하나
3. 그 원인을 확인하는 최소 진단 명령
4. 허용할 최소 코드 또는 설정 수정
5. 수정 후 검증 명령
6. PR comment용 세 줄: 원인, 변경, 증거
여러 사람이 같은 repository를 만질 때는 범위도 적습니다. 이 slug만 확인하기, reports 수정 금지, unrelated change 되돌리지 않기, frontmatter identity fields 보존하기. 이런 제약이 있어야 다른 작업자와 충돌하지 않습니다.
네 가지 실무 use case
첫 번째는 Astro 다국어 콘텐츠 사이트입니다. locale 하나의 frontmatter 오류, 닫히지 않은 MDX code fence, 빠진 OGP 이미지, 잘못된 내부 링크가 build를 깨뜨릴 수 있습니다. Claude Code에는 target slug의 10개 파일만 비교하고 YAML, code fence, body 길이를 확인하게 합니다.
두 번째는 Node CLI나 package import 실패입니다. Cannot find module은 항상 dependency 누락이 아닙니다. typo, 생성 파일 누락, exports 제한, ESM/CJS 혼용일 수 있습니다. dependency를 바꾸기 전에 node -p "require.resolve('package-name')"나 파일 존재 확인을 먼저 합니다.
세 번째는 CI에서만 실패하는 경우입니다. permission, case-sensitive path, Node 버전 차이, secret 이름 오류, proxy 설정 누락이 원인일 수 있습니다. 애플리케이션 코드를 바꾸기 전에 CI OS, working directory, Node version, env var 이름, write target을 정리합니다.
네 번째는 test expectation drift입니다. Expected ... received를 snapshot update로 덮는 것은 쉽지만 regression을 승인할 수 있습니다. CTA 링크, 가격 문구, Gumroad 링크, training form, article metadata는 의도한 변경인지 먼저 확인합니다.
구체적인 함정
첫 번째 함정은 로그 끝만 읽는 것입니다. 마지막 stack trace는 원인이 아니라 결과일 수 있습니다. 첫 실패 줄과 그 앞 30줄을 보존합니다.
두 번째 함정은 dependency를 너무 빨리 올리는 것입니다. package 변경은 lockfile, CI cache, runtime 호환성까지 건드립니다. import path typo라면 dependency upgrade는 review를 어렵게 만들 뿐입니다.
세 번째 함정은 build 성공에서 멈추는 것입니다. 공개 사이트라면 /en/products/, /en/training/, 무료 PDF form, h1, canonical까지 확인해야 합니다.
네 번째 함정은 작업 중 정리를 허용하는 것입니다. build-fix PR은 가설이 선명해야 합니다. formatting, refactor, dependency upgrade, content rewrite를 섞으면 어떤 변경이 문제를 해결했는지 알 수 없습니다.
제품과 상담 CTA
이 루프를 반복 가능한 prompts, checklists, setup material로 만들고 싶다면 ClaudeCodeLab products를 보세요. 팀이 CI gate, CLAUDE.md, permission rules, review receipts, production verification을 실제 repository에 맞춰 정리해야 한다면 Claude Code training and consultation이 맞습니다.
이어 읽을 글로는 permission audit checklist와 CI/CD setup이 좋습니다. 개인은 무료 PDF로 명령 습관을 만들고, 팀은 공유 prompt, 공유 증거 형식, 승인 책임자를 먼저 정하는 편이 현실적입니다.
실제로 달라진 점
이 루프를 쓰면 patch가 작아집니다. 전체 로그를 한번에 맡기기보다 첫 실패 줄, 가설 하나, 검증 명령 하나로 시작하면 frontmatter 누락, generated file 누락, import path typo, CI permission 문제를 더 빨리 나눌 수 있습니다. 가장 큰 장점은 첫 수정 자체가 아니라 다음 실패 때 재사용할 수 있는 짧은 증거가 남는 것입니다.
무료 PDF: Claude Code 치트시트
이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.
개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.
작성자 소개
Masa
Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.
관련 글
Obsidian 메모를 CLAUDE.md로 바꾸는 Claude Code 워크플로
Obsidian 작업 메모를 CLAUDE.md 운영 노트로 정리해 Claude Code 세션의 문맥 반복을 줄입니다.
Claude Code Revenue CTA Routing: 글에서 PDF, Gumroad, 상담으로 보내기
독자 의도에 따라 무료 PDF, Gumroad 상품, 상담으로 나누는 Claude Code CTA 설계입니다.
Claude Code 팀 인계 규칙: 리뷰 증거, 권한, 롤백, 수익 경로까지 넘기는 법
Claude Code 작업을 팀에 넘길 때 필요한 증거, 권한 규칙, 롤백, 무료 PDF, Gumroad, 상담 경로 체크리스트.