DEV Community

Cover image for A Docker Build Failure That Had Nothing to Do With Docker
Janice
Janice

Posted on

A Docker Build Failure That Had Nothing to Do With Docker

A local Docker build suddenly started failing with a MODULE_NOT_FOUND error, while the exact same build continued to pass in CI/CD.

Here’s how I tracked it down.

About the bug

Previously, I ran into a strange bug when building my Docker image locally:

node:internal/modules/cjs/loader:1424
  throw err;
  ^

Error: Cannot find module 'apps/web/node_modules/next/dist/bin/next'
    at Module._resolveFilename (node:internal/modules/cjs/loader:1421:15)
    at defaultResolveImpl (node:internal/modules/cjs/loader:1059:19)
    at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1064:22)
    at Module._load (node:internal/modules/cjs/loader:1227:37)
    at TracingChannel.traceSync (node:diagnostics_channel:328:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:245:24)
    at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)
    at node:internal/main/run_main_module:33:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}
Enter fullscreen mode Exit fullscreen mode

What made the issue particularly confusing was that the exact same Docker build had been working perfectly in CI/CD, while consistently failing on my local machine.

Before discussing the fix, here is some context about the project:

  • It is a pnpm monorepo containing both frontend and backend workspaces.
  • pnpm dev had always worked locally.
  • The Docker build pipeline had always worked in CI/CD.
  • The version of next had never changed since the project was created.

During the debugging session, I noticed that I had pnpm 9.x.x upgraded to 10.x.x at some point.

That observation led me to test whether the problem could be reproduced outside Docker. Surprisingly, I got the same error:

➜ fileops git:(main) ✗ pnpm --filter web exec next build 
`next` is not Found
Enter fullscreen mode Exit fullscreen mode

Hmmm, interesting. As a final experiment, I ran

pnpm install
Enter fullscreen mode Exit fullscreen mode

and it fixed the issue immediately.

But why? And... What happened?

Solution

Here's my most valuable takeaway:

When Docker builds work in CI/CD but fail locally, suspect local-only files entering the Docker build context.

In my case, CI worked because it built from a clean checkout. Local builds failed because stale workspace-level node_modules (under apps/web/) from a pnpm monorepo leaked into the Docker context. After upgrading pnpm from 9.x to 10.x, the local dependency layout was stale. pnpm dev still worked, so the issue stayed hidden until Docker ran a production build.

The fix was twofold:

1. Regenerate local dependencies:

pnpm install
Enter fullscreen mode Exit fullscreen mode

Even though my NextJS version had not changed, pnpm's generated node_modules structure had become stale after upgrading pnpm. Pnpm uses a link structure for managing packages, and the algorithm for generating the link structure might change from one version to another.

If you'd like to know more, check out these links:

2. Make .dockerignore monorepo-safe:

- node_modules
+ **/node_modules
**/.next
Enter fullscreen mode Exit fullscreen mode

My original .dockerignore only excluded the root-level node_modules directory. In a monorepo, workspace-level dependency directories can also exist, and excluding them helps prevent stale workspace dependencies and NextJS build artifacts from entering the Docker build context.

Looking back, pnpm install sounds almost unrelated to a Docker build failure. Have you run into bugs where the actual solution only made sense in hindsight?

Top comments (0)