Skip to content
Latchkey

Vite "Could not load <file> (imported by <file>)" - Fix in CI

During vite build, Rollup resolved an import to a path but then failed to read the file from disk. The specifier mapped to something that does not exist - a missing file, a casing mismatch, or an extension the resolver did not append.

What this error means

The build fails with Could not load <path> (imported by <file>): ENOENT: no such file or directory. It surfaces in the production Rollup pass, so vite dev may have tolerated it.

vite output
error during build:
Could not load /app/src/utils/format (imported by src/App.tsx):
ENOENT: no such file or directory, open '/app/src/utils/format'

Diagnose it: is it resolution, transform, or memory?

Bundler failures in CI fall into three families and the error text often points at the wrong one. A module that resolves on your machine and not on the runner is nearly always case sensitivity or a missing optional dependency; a transform error is a config or version mismatch; and an unexplained kill with no stack is the out-of-memory reaper, not a build error at all.

Terminal
# 1. resolution: does the file exist with EXACTLY that case?
git ls-files | grep -i "the/imported/path"

# 2. transform: what versions is CI actually resolving?
npm ls webpack vite rollup esbuild typescript 2>/dev/null | head -20

# 3. memory: was it killed rather than failed?
#    exit 137 = SIGKILL (OOM). Nothing in the bundler log will explain it.
node --max-old-space-size=4096 node_modules/.bin/vite build

Common causes

File missing or wrong case

The imported file does not exist at that path, or its casing differs from the import. Case-sensitive Linux runners fail where macOS did not.

Missing extension the build does not infer

Importing without an extension where the resolver cannot guess it (or an asset import without a matching plugin) leaves Rollup with a path it cannot read.

How to fix it

Verify the file and its exact case

Confirm the target exists at the imported path with matching casing.

Terminal
ls -la src/utils/   # check for format.ts vs Format.ts
# correct the import or rename the file to match

Make extensions resolvable

Add the extension to the import, or configure resolve.extensions so the build can append it.

vite.config.ts
// vite.config.ts
export default defineConfig({
  resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'] },
})

Make the build reproducible before you debug it

  • Pin the Node major in setup-node and in engines. A bundler that resolves native bindings will pick a different prebuilt binary across majors.
  • Delete node_modules locally and reinstall from the lockfile before concluding the runner is at fault; most "works locally" reports are stale local state.
  • Set CI=true locally to reproduce. Several toolchains change behaviour under it, including treating warnings as errors.
  • Exit code 137 is an out-of-memory kill. Raise --max-old-space-size or move to a larger runner rather than searching the bundler config.

How to prevent it

  • Run vite build in CI so disk-load failures surface before deploy.
  • Match import casing to filenames for case-sensitive runners.
  • Keep resolve.extensions aligned with the extensions you omit in imports.

Frequently asked questions

What causes Vite "Could not load <file> (imported by <file>)"?
There are 2 common causes: file missing or wrong case and missing extension the build does not infer. The imported file does not exist at that path, or its casing differs from the import.
How do I fix Vite "Could not load <file> (imported by <file>)"?
There are 2 fixes depending on which cause you have: verify the file and its exact case and make extensions resolvable. Work through them in order, since the first is the most common.
What does Vite "Could not load <file> (imported by <file>)" actually mean?
The build fails with Could not load <path> (imported by <file>): ENOENT: no such file or directory.
How do I stop Vite "Could not load <file> (imported by <file>)" happening again?
Run vite build in CI so disk-load failures surface before deploy. 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