BlueByte
YN0018Fixed

Yarn: install이 integrity checksum mismatch로 실패

작성 Haneul Seo2026년 9월 9일 업데이트9 min

안녕하세요, BlueByte입니다. yarn install이 Integrity check failed(최신 Yarn에서는 에러 코드 YN0018)로 멈춰도 여러분 코드에는 문제가 없습니다. Yarn이 가지고 있는 tarball(방금 받았거나 캐시에 있던)의 해시를 yarn.lock에 기록된 checksum과 비교했는데 일치하지 않아, 믿을 수 없는 패키지를 link하기를 거부한 것입니다. 오늘은 이 메시지의 뜻, 지금 어떤 Yarn을 쓰는지 확인하는 법(해결이 다릅니다), checksum이 어긋나는 이유, 원인 확인, 계열별 해결, 그리고 예방까지 하나씩 짚어보겠습니다.

Integrity check failed(그리고 YN0018)이 알려주는 것

Yarn Classic(v1)은 패키지와 계산한 해시를 이름과 함께 보여줍니다:

error Integrity check failed for "left-pad" (computed integrity doesn't match our records, got "sha512-...")

최신 Yarn(Berry, v2+)은 같은 실패에 에러 코드를 붙입니다. Yarn 에러 인덱스는 YN0018을 CACHE_CHECKSUM_MISMATCH라 부르며 "The checksum of a package from the cache doesn't match what the lockfile expects."로 정의합니다. 두 형태 모두 같은 뜻입니다 — Yarn이 가진 바이트로 계산한 해시가 lockfile이 기대하는 해시와 다르다는 것입니다. Yarn은 제 역할을 하는 중입니다: 바이트가 바뀐 패키지를 말없이 설치하지 않습니다.

먼저 지금 어떤 Yarn을 쓰는지 확인하기

해결 명령과 설정 키가 두 계열에서 갈리므로, 무엇이든 건드리기 전에 버전부터 확인합니다:

yarn --version

1.x는 Yarn Classic, 2.x·3.x·4.x는 최신 Yarn(Berry)입니다. 저장소는 package.json의 packageManager나 .yarnrc.yml의 yarnPath로 자체 버전을 고정할 수 있어, PATH의 Yarn이 프로젝트가 실제로 쓰는 Yarn과 늘 같지는 않습니다 — 명령은 프로젝트 디렉터리 안에서 실행하세요.

checksum이 어긋나는 이유

해시가 달라지는 데는 몇 가지 구체적 이유가 있습니다:

  • 로컬 캐시가 손상됐습니다 — 다운로드 중단, 설치 중단, 디스크 문제로 잘리거나 변형된 tarball이 남았습니다.
  • lockfile이 다른 레지스트리 기준으로 만들어졌습니다 — 사설 미러나 프록시가 tarball을 다시 포장해, 바이트(와 해시)가 lock에 기록된 것과 다릅니다.
  • 누군가 디버깅 중 캐시 아카이브를 손으로 고쳤습니다 — Yarn 문서는 이를 YN0018의 가장 흔한 계기로 꼽습니다.
  • Yarn 버전이나 해시 알고리즘을 바꿨습니다 — 오래된 lock이 새 resolver가 다르게 계산하는 checksum을 담고 있습니다.
  • 드물게 레지스트리가 같은 버전을 다른 바이트로 재배포했습니다 — 있어서는 안 되지만 사설 레지스트리에서 간혹 일어납니다.

이 중 어느 것도 의존성 자체의 버그가 아닙니다. 불일치는 디스크 위의 tarball과 lock의 기록 사이에 있습니다.

메시지 읽기: 캐시 손상인가, 패키지가 바뀐 것인가

불일치가 어디서 나타나는지가 어디를 봐야 할지 알려줍니다. 한 패키지에서, 그것도 내 컴퓨터에서만 난다면 로컬 캐시 손상을 의심하세요. 팀 전체나 CI가 같은 패키지에서 겪는다면 레지스트리나 lockfile을 의심하세요. 실제로 캐시에 무엇이 있는지 봅니다:

yarn cache dir     # Classic: prints the global cache path
ls .yarn/cache     # Berry: per-project cache of .zip archives

동료의 컴퓨터에서 새로 clone해도 불일치가 남는다면, lockfile 자체가 잘못된 checksum을 담고 있어 캐시만 지워서는 안 되고 다시 생성해야 합니다.

최신 Yarn(Berry)에서 고치기

Berry의 가장 깔끔한 해결은 문제 항목을 비우고 다시 받는 것입니다. checksumBehavior 설정이 불일치 시 동작을 정합니다 — throw(기본), reset, update, ignore. 한 번만 비우고 다시 받으려면 reset을 씁니다:

YARN_CHECKSUM_BEHAVIOR=reset yarn install

문서에 따르면 reset은 "the cache entry will be purged and fetched anew"를 뜻합니다. 새 바이트가 정당함을 확인했다면(예: 신뢰하는 미러), 모든 checksum을 다시 받아 재검증하는 쪽을 쓰세요:

yarn install --check-cache

문서는 --check-cache를 "always refetch the packages and ensure that their checksums are consistent"로 설명합니다. 최후의 수단으로 update는 계산된 해시를 yarn.lock에 다시 써넣습니다 — 새 바이트의 출처를 신뢰할 때만 하세요.

Yarn Classic(v1)에서 고치기

Classic에는 checksumBehavior가 없습니다. 캐시를 지우고 재설치합니다. 오래된 node_modules와 그 integrity 마커를 지우고, 캐시를 비운 뒤 새로 설치하세요:

yarn cache clean
rm -rf node_modules
yarn install

lock에 기록된 해시가 틀린 경우(예: 레지스트리를 옮긴 뒤)라면 다시 생성합니다:

yarn install --update-checksums

이는 "update checksums in the yarn.lock lockfile if there's a mismatch between them and their package's checksum"에 해당합니다. 고쳐진 lockfile을 커밋해 모두가 같은 값을 받게 하세요.

실제 사례: CI에서 절반만 받아진 패키지

CI 작업이 yarn install 도중 강제 종료됩니다. 다음 빌드가 이전 실행의 캐시를 복원하고 react-dom@npm:18.3.1에서 YN0018로 실패합니다. 이 패키지 하나에서만, 그것도 CI에서만 — 전형적인 캐시 손상 신호입니다. 그 단계를 YARN_CHECKSUM_BEHAVIOR=reset yarn install로 바꾸자 러너가 잘린 .zip을 비우고 다시 받아, 해시가 맞고 빌드가 통과합니다. lockfile은 하나도 바뀌지 않았습니다 — 기록된 checksum은 내내 옳았고, 캐시의 바이트가 틀렸던 것입니다.

설치가 깨끗한지 확인하고 재발을 막기

CI가 어차피 써야 할 플래그, immutable 설치로 증명합니다:

yarn install --immutable
➤ YN0000: · Done in 3s 421ms

--immutable은 "if the lockfile was to be modified" 중단하므로, checksum이 맞는 깨끗한 설치는 lock 변경 없이 0으로 끝납니다. 재발을 막으려면: yarn.lock을 커밋하고 캐시를 손으로 고치지 마세요. packageManager로 Yarn 버전 하나를 고정해 모두가 같은 방식으로 해시를 계산하게 하세요. CI에서는 --immutable(Berry는 --immutable-cache도)을 써서, 어긋나는 checksum이 조용히 "고쳐지는" 대신 파이프라인에서 크게 실패하게 하세요.

ERESOLVE·registry 404와 어떻게 다른가

checksum 불일치는 바뀐 바이트의 문제입니다. ERESOLVE(npm)나 Yarn의 peer-dependency 에러는 조율할 수 없는 버전의 문제로, 다운로드가 아니라 resolver의 일입니다. 404 Not Found/"couldn't find package"는 그 버전이 레지스트리에 아예 없다는 뜻입니다. 메시지가 아카이브나 integrity가 "doesn't match"라고 하면 이 글의 경우이고, 버전을 resolve하거나 찾을 수 없다고 하면 캐시를 지워도 소용없습니다.

관련 질문

그냥 yarn.lock을 지우면 해결되나요?

아니요. 잘못된 checksum 하나가 아니라 고정된 모든 버전을 버리게 되고, 새로운 resolution 문제를 부릅니다. 문제 패키지만 다시 받거나(Berry는 reset, Classic은 yarn cache clean) --update-checksums로 해시를 다시 생성하고, lockfile은 소스 관리에 두세요.

YARN_CHECKSUM_BEHAVIOR=reset과 =update는 무엇이 다른가요?

reset은 캐시 파일을 비우고 다시 받아, lockfile의 해시를 기준으로 유지합니다. update는 캐시에 있는 것에 맞춰 lockfile을 다시 씁니다. lock을 신뢰하면 reset, 새 바이트를 의도적으로 신뢰할 때만 update를 쓰세요.

내 노트북이 아니라 CI에서만 에러가 납니다.

로컬 캐시에는 정상 사본이 있고, CI가 손상되거나 어긋난 사본을 복원한 것입니다. CI 캐시를 비우고(Berry는 reset, Classic은 yarn cache clean) 다시 실행하세요. 새 실행에서도 계속된다면 CI 레지스트리가 lock을 만든 곳과 다릅니다.

--update-checksums는 안전한가요?

새 바이트의 출처를 신뢰할 때만 안전합니다. 계산된 해시를 yarn.lock에 써넣으므로, 변조된 tarball이 새 '기대값'이 될 수 있습니다. 레지스트리나 미러를 일부러 바꾼 게 아니라면 reset이나 평범한 재다운로드를 먼저 쓰세요.

Berry에서도 node_modules를 지워야 하나요?

보통은 아닙니다. Berry는 .yarn/cache에서 설치하므로 reset으로 캐시 항목만 비우면 충분합니다. Classic은 캐시와 함께 node_modules를 지우세요 — 거기 쓰인 .yarn-integrity 마커가 오래돼 검사를 다시 유발할 수 있습니다.

참고 자료

Haneul Seo

Infrastructure engineer · 10+ years running Linux fleets

같은 카테고리 다른 글

detected dubious ownershipFixed

Git: fatal: detected dubious ownership in repository

Git 2.35.2의 CVE-2022-24765 수정 이후, Git은 작업 트리나 .git 디렉터리의 소유자가 명령을 실행한 사용자와 다르면 저장소를 읽지 않습니다. 컨테이너, CI 작업, sudo 세션, 공유 드라이브에서 주로 나타납니다. 저장소가 내 것이어야 한다면 소유권을 바로잡고, 아니라면 global 설정의 safe.directory에 정확한 경로를 추가하세요 — Git은 이 설정을 저장소 자신의 설정에서는 무시합니다.

Git
failed calling webhookFixed

Kubernetes: Internal error occurred: failed calling webhook

admission webhook이 쓰기 요청 앞에 서 있는데 API server가 응답을 받지 못했고, 기본값인 failurePolicy: Fail이 그 침묵을 거부로 바꾼 것입니다. 메시지 끝부분이 곧 진단입니다 — context deadline exceeded는 호출이 도달하지 못한 것, no endpoints available은 떠 있는 게 없는 것, x509 줄은 API server가 webhook 인증서를 신뢰하지 않는 것입니다. 원인마다 해결이 다르고, 어느 것도 매니페스트 문제가 아닙니다.

Kubernetes
1205Fixed

MySQL: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

다른 트랜잭션이 쥐고 있는 행 잠금을 innodb_lock_wait_timeout 만큼 기다리다 포기한 것입니다. sys.innodb_lock_waits 가 막고 있는 세션을 지목하고 KILL 문까지 만들어 주며, blocking_query 가 NULL 이면 블로커가 열린 트랜잭션 위에서 놀고 있다는 뜻입니다. 재시도 로직이 가장 자주 틀리는 지점은 따로 있습니다. 기본값에서는 타임아웃된 문장 하나만 롤백되므로, 트랜잭션은 그대로 열린 채 앞서 잡은 잠금을 전부 쥐고 있습니다.

MySQL
MISCONFFixed

Redis: MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk

읽기는 되는데 모든 쓰기가 거부됩니다. 마지막 백그라운드 저장이 실패했고 stop-writes-on-bgsave-error 기본값이 yes 이기 때문입니다. 진짜 원인은 로그에 적혀 있습니다 — 디스크 공간 부족, redis 사용자가 쓸 수 없는 dir, rename 시점의 read-only 마운트, 또는 fork 가 Cannot allocate memory 로 실패하는 경우입니다. 원인을 고치고 BGSAVE 한 번만 돌리면 재시작 없이 쓰기가 돌아옵니다. rdb_last_bgsave_status 가 err 에서 ok 로 바뀝니다. stop-writes-on-bgsave-error no 는 쓰기를 즉시 되살리지만 스냅샷은 여전히 실패한 상태로 두므로, 해결이 아니라 의도한 맞교환으로 다뤄야 합니다.

Redis
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryFixed

Node.js: FATAL ERROR: Reached heap limit — JavaScript heap out of memory (종료 코드 134)

V8 힙에는 시스템 메모리와 Node 릴리스에서 유도되는 자기만의 천장이 있고, 가진 RAM 보다 훨씬 낮은 경우가 흔합니다. 빌드나 서버가 거기 닿으면 V8 은 FATAL ERROR: Reached heap limit 과 종료 코드 134 로 스스로 중단합니다. v8.getHeapStatistics().heap_size_limit 으로 실제 한도를 읽은 뒤, 큰 작업은 --max-old-space-size(MiB)나 NODE_OPTIONS 로 올리고, 컨테이너 안에서는 cgroup 한도보다 낮게 잡고, 오래 도는 프로세스의 누수는 --heapsnapshot-near-heap-limit 으로 잡으세요. FATAL ERROR 줄 없이 137 로 끝나면 컨테이너 kill 이지 이 오류가 아닙니다.

Node.js
exec /docker-entrypoint.sh: exec format errorFixed

Docker: 컨테이너 시작 직후 "exec format error" — 플랫폼이 다른 이미지, 에뮬레이터 없음, 셔뱅 없는 스크립트

컨테이너가 첫 명령에서 exec format error 로 끝납니다. 커널의 ENOEXEC, 즉 파일은 있지만 여기서는 실행할 수 없다는 뜻입니다. 실제로는 한 CPU 아키텍처에서 빌드한 이미지(Apple 실리콘 Mac은 linux/arm64 를 만듭니다)를 binfmt_misc 에 QEMU 핸들러가 없는 다른 아키텍처(x86_64 서버)에서 돌리거나, 엔트리포인트 스크립트의 첫 줄이 셔뱅이 아닌 경우입니다. uname -m, docker image inspect, ls /proc/sys/fs/binfmt_misc 로 원인을 가르고, docker buildx build --platform 을 명시(또는 두 플랫폼 매니페스트 목록 발행)하거나, 에뮬레이션이 목적이면 QEMU 등록과 --platform, 스크립트라면 #!/bin/sh 한 줄로 해결합니다.

Docker