Introduction

npm ci is designed for reproducible CI builds. It verifies each downloaded package against the integrity hash stored in package-lock.json. When the hash does not match - due to registry tampering, cache corruption, or an outdated lock file - npm ci fails immediately. This is a security feature that prevents supply chain attacks but can also block legitimate builds.

Symptoms

  • npm ERR! code EINTEGRITY
  • npm ERR! sha512-abc123... integrity checksum failed when using sha512: wanted sha512-abc... but got sha512-def...
  • npm ERR! Invalid response body while trying to fetch
  • npm ci fails but npm install succeeds
  • Build fails in CI but works locally

``` npm ERR! code EINTEGRITY npm ERR! Verification failed while extracting lodash@4.17.21: npm ERR! sha512-abc123... integrity checksum failed when using sha512: npm ERR! wanted sha512-abc123... npm ERR! but got sha512-def456... (25643 bytes)

npm ERR! A complete log of this run can be found in: npm ERR! /root/.npm/_logs/2024-01-15T10_30_00_000Z-debug-0.log ```

Common Causes

  • package-lock.json out of sync with package.json
  • npm cache corrupted with wrong package contents
  • Registry serving different package contents than expected
  • Switched npm registry (npmjs.org to private registry)
  • Git merge conflict in package-lock.json not resolved correctly

Step-by-Step Fix

  1. 1.Clear npm cache and retry:
  2. 2.```bash
  3. 3.# Clear corrupted cache
  4. 4.npm cache clean --force

# Verify cache integrity npm cache verify

# Retry ci npm ci ```

  1. 1.Regenerate package-lock.json:
  2. 2.```bash
  3. 3.# Remove node_modules and lock file
  4. 4.rm -rf node_modules package-lock.json

# Regenerate from package.json npm install

# This creates a fresh package-lock.json with correct hashes # Commit the new lock file git add package-lock.json git commit -m "Regenerate package-lock.json"

# Now npm ci will work npm ci ```

  1. 1.Check for registry issues:
  2. 2.```bash
  3. 3.# Check which registry is configured
  4. 4.npm config get registry
  5. 5.# Should be: https://registry.npmjs.org/

# If using a private registry, verify it serves correct packages npm view lodash@4.17.21 dist.integrity # Compare with your package-lock.json

# Switch back to npmjs if needed npm config set registry https://registry.npmjs.org/ ```

  1. 1.Handle registry switching in CI:
  2. 2.```yaml
  3. 3.# GitHub Actions
  4. 4.- name: Setup npm registry
  5. 5.run: |
  6. 6.npm config set registry https://registry.npmjs.org/
  7. 7.npm cache clean --force
  8. 8.npm cache verify
  • name: Install dependencies
  • run: npm ci

# For private registries, use .npmrc # .npmrc registry=https://registry.npmjs.org/ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} @myorg:registry=https://npm.pkg.github.com ```

  1. 1.Verify package-lock.json consistency:
  2. 2.```bash
  3. 3.# Check if lock file is consistent
  4. 4.npm ls # Shows dependency tree, errors on inconsistencies

# Verify all packages in lock file match package.json npm install --package-lock-only # If package.json changed, this updates package-lock.json without touching node_modules

# Check for lock file drift git diff HEAD~1 package-lock.json | head -50 ```

Prevention

  • Always commit package-lock.json to version control
  • Run npm ci instead of npm install in CI/CD pipelines
  • Add npm cache verify as a CI step before npm ci
  • Use .npmrc to pin the registry URL
  • Never manually edit package-lock.json
  • Run npm install (not npm ci) when updating dependencies, then commit the new lock file
  • Use npm audit to check for known vulnerabilities in dependencies
  • Consider using npm ci --ignore-scripts for faster builds when scripts are not needed