Skip to content
Latchkey

Angular "Module not found: Error: Can't resolve" in CI

The Angular build (webpack/esbuild under @angular-devkit/build-angular) could not resolve an import specifier. The path is wrong, the package is not installed, or a case-sensitive path differs between your machine and the Linux runner.

What this error means

ng build fails with "Module not found: Error: Can't resolve './foo' in '/home/runner/work/app/app/src/app'" pointing at a specific import.

ng build
./src/app/app.component.ts:5:0-42
Module not found: Error: Can't resolve './services/user.service' in '/home/runner/work/app/app/src/app'

Diagnose it: what is different about the runner?

A build that passes locally and fails on a runner differs in a small number of predictable ways. Check those before changing build configuration, because the build config is usually not the thing that changed.

.github/workflows/ci.yml
- run: |
    node --version && npm --version
    echo "NODE_ENV=$NODE_ENV  CI=$CI"
    nproc && free -h && df -h /
    ls -la node_modules/.bin | head

Common causes

Case-sensitive path mismatch on Linux

macOS and Windows treat file names case-insensitively; the Linux runner does not, so User.service vs user.service fails only in CI.

A missing dependency or a wrong relative path

The imported package is not in the lockfile, or a relative path was renamed/moved without updating the import.

How to fix it

Match the import to the real file name and case

  1. Compare the import string against the actual file name, including case.
  2. Rename the import or the file so they match exactly.
  3. For a package import, confirm it is installed with npm ls <pkg>.
app.component.ts
// file is user.service.ts
import { UserService } from './services/user.service';

Verify path aliases resolve in the build

If you use tsconfig paths, ensure the alias maps to a real directory that exists after install on the runner.

tsconfig.json
"paths": {
  "@app/*": ["src/app/*"]
}

The three that account for most of them

  • Case sensitivity. Linux runners are case sensitive, macOS is not. An import with the wrong case resolves locally and fails in CI.
  • Out of memory. Exit code 137 is a SIGKILL from the kernel, not a build error. Raise --max-old-space-size or use a larger runner.
  • devDependencies pruned. NODE_ENV=production makes npm ci skip devDependencies, so the build tool itself goes missing. Set it after install, not before.

How to prevent it

  • Keep import paths case-exact so Linux runners match your machine.
  • Install all imported packages and commit the lockfile.
  • Validate tsconfig path aliases against real directories.

Frequently asked questions

What causes Angular "Module not found: Error: Can't resolve" in CI?
There are 2 common causes: case-sensitive path mismatch on linux and a missing dependency or a wrong relative path. macOS and Windows treat file names case-insensitively; the Linux runner does not, so User.service vs user.service fails only in CI.
How do I fix Angular "Module not found: Error: Can't resolve" in CI?
There are 2 fixes depending on which cause you have: match the import to the real file name and case and verify path aliases resolve in the build. Work through them in order, since the first is the most common.
What does Angular "Module not found: Error: Can't resolve" in CI actually mean?
ng build fails with "Module not found: Error: Can't resolve './foo' in '/home/runner/work/app/app/src/app'" pointing at a specific import.
How do I stop Angular "Module not found: Error: Can't resolve" in CI happening again?
Keep import paths case-exact so Linux runners match your machine. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card