기술 · 실용 가이드
npm ci가 package-lock 불일치를 알릴 때: 재생성 전에 manifest·설정·npm 버전을 감사하세요
실패 입력을 먼저 보존하세요. 같은 EUSAGE라도 의존성 변경, 프로젝트 설정 차이, 오래된 lockfile, npm 버전별 resolver 동작이 원인일 수 있습니다.

npm ci가 package.json과 package-lock.json이 동기화되지 않았다고 보고하는 것은 고정되어야 할 의존성 트리를 다시 쓰지 않겠다는 뜻입니다. 이 메시지는 일관성 검사가 실패했다는 신호이지 하나의 보편적 원인은 아닙니다. 실패 입력을 보존하고 무엇이 바뀌었는지 입증한 뒤 manifest, 설정, npm 버전 또는 생성된 lockfile 중 무엇을 고칠지 결정합니다.
처음부터 package-lock.json을 삭제하거나 CI를 npm install로 바꾸거나 --force를 추가하지 마세요. 실패를 설명할 비교 자료가 사라지고 작은 변경이 큰 의존성 트리 변동으로 커질 수 있습니다. 안전한 수정은 정확한 Missing 또는 Invalid 항목을 설명하고, 의도한 정책에서 재현되며, 검토 가능한 lockfile diff를 남겨야 합니다.
1. EUSAGE를 일관성 보호 장치로 읽기
npm ci는 자동화되고 재현 가능한 설치를 위한 명령입니다. lockfile을 요구하고 기존 node_modules를 제거한 뒤 설치하며 package.json이나 lockfile을 쓰지 않습니다. 불일치하면 종료하여 검토되지 않은 의존성 변경을 CI가 수용하지 않게 합니다.
다른 명령을 시도하기 전에 전체 오류를 복사합니다. 모든 Missing/Invalid 줄, 작업 디렉터리, repository root 또는 workspace에서 실행했는지 보존합니다. 첫 package와 버전 범위가 분기를 알려 주지만 마지막 npm install 안내가 재생성만이 정답임을 뜻하지는 않습니다.
2. manifest·lockfile·환경의 읽기 전용 원장 만들기
정확한 commit과 package.json/package-lock.json 수정 여부를 기록합니다. dependencies, devDependencies, optionalDependencies, peerDependencies, bundledDependencies, overrides, workspaces를 읽습니다. lockfileVersion, packages[""] 루트, 오류가 가리킨 package path를 확인하고 생성된 integrity나 의존성 필드를 손으로 편집하지 않습니다.
node --version, npm --version, 프로젝트 .npmrc, 관련 환경 변수, 정확한 CI 명령을 기록합니다. legacy-peer-deps, strict-peer-deps, install-links, omit/include, workspace selector를 포함하고 registry token과 자격 증명은 가립니다.
3. 의도된 manifest 변경과 실수 분리하기
package.json이 lockfile 뒤에 바뀌었다면 의존성 변경이 의도되고 검토되었는지 판단합니다. 직접 의존성이 추가됐지만 packages[""].dependencies에 없다면 manifest drift입니다. overrides, workspace membership, package-manager 설정도 일반 dependencies가 같아도 트리를 바꿀 수 있습니다.
의도된 변경은 지정 npm 버전과 설정을 쓰는 통제된 개발 환경에서 lockfile을 재생성합니다. 실수라면 검토된 manifest를 복원합니다. CI가 매번 트리를 고치게 하지 말고 생성 lockfile을 명시적 source change로 검토합니다.
4. lockfile을 만든 install policy 재현하기
공식 npm ci 문서는 트리 형성 flag로 만든 lockfile은 같은 flag로 설치해야 한다고 설명합니다. legacy-peer-deps가 흔한 예입니다. 모두에게 필요한 설정은 프로젝트 .npmrc에 commit하고 개인 설정이 repository tree를 몰래 결정하지 않게 합니다.
같은 npm major, project .npmrc, workspace command로 clean checkout을 비교합니다. flag 추가 때만 통과한다면 그것이 repository policy인 이유를 설명한 뒤 commit합니다. 기록되지 않은 성공 명령은 문제를 다른 machine으로 옮겼을 뿐일 수 있습니다.
5. npm 버전 동작과 손상된 lockfile 구분하기
manifest, lockfile, 설정이 같은데 npm 버전에 따라 실패가 달라지면 파일을 쓰기 전에 작은 version matrix를 재현합니다. 지원 버전과 인접 버전의 오류 전문을 저장합니다. 최근 upstream 사례처럼 npm install 후 npm ci가 거부되는 resolver path는 gate를 무시할 이유가 아니라 escalation 증거입니다.
실제로 손상되거나 오래된 lockfile에는 parse failure, 루트 metadata 누락, 불가능한 package map, conflict marker, 알려진 format transition 같은 구체적 증거가 필요합니다. 원본을 보존하고 의도한 toolchain으로 한 번 재생성해 전체 diff를 비교합니다.
6. clean checkout에서 최소 수정 검증하기
증거 기반 최소 수정 뒤 clean checkout에서 시작합니다. 의도한 Node/npm 버전과 commit된 프로젝트 설정만 로드하고 CI와 같은 npm ci를 실행합니다. lockfile이 바뀌지 않는지, 올바른 workspace, lifecycle script, 기존 test/build를 확인합니다.
lockfile diff를 의존성 코드처럼 검토합니다. 루트 범위, resolved 버전, integrity, peer 관계, 삭제가 의도와 맞아야 합니다. 다시 실패하면 새 오류를 보존하고 원장의 분기로 돌아가며 우연히 통과할 때까지 재생성을 반복하지 않습니다.
