6 months ago
BuildKit cache mount corrupted at /app/node_modules/@types/node — error persists across Nixpacks and Dockerfile builds, across multiple deploys. Error: cannot copy to non-directory: /var/lib/buildkit/runc-overlayfs/cachemounts/buildkitXXXXXXXXXX/app/node_modules/@types/node
1 Replies
Status changed to Awaiting Railway Response Railway • 6 months ago
a month ago
That path identifies a cache-mount type collision, not an application compile error: the persisted mount already has node_modules/@types/node as a non-directory entry (often a stale symlink or partial install), while the next dependency layer needs to create/copy a directory there. Repeating deploys reattaches the same corrupt mount, which explains why changing from Nixpacks to a Dockerfile did not clear it.
Use one no-cache build as the discriminator:
-
Set the service variable
NO_CACHE=1, apply the staged change, then run Deploy Latest Commit (orrailway up). Do not use Restart; it reuses the built image. Railway's current build configuration documentsNO_CACHE=1as the switch that disables build-layer reuse, and Deploy Latest Commit performs a full rebuild. -
Ensure neither the repository nor upload context contains dependencies:
git ls-files node_modules git ls-files -s | grep 'node_modules/@types/node'Both should be empty. Add
node_modulesto.gitignoreand.dockerignore; remove any committed file/symlink under that path. Do not print environment files or registry tokens. -
Do not cache
/app/node_modules. Cache the package manager's download store and recreatenode_modulesdeterministically from the lockfile. For npm, the dependency stage should follow this shape:# syntax=docker/dockerfile:1 FROM node:20-bookworm-slim AS build WORKDIR /app COPY package.json package-lock.json ./ RUN --mount=type=cache,id=s/<service-id>-/root/.npm,target=/root/.npm \ npm ci --cache /root/.npm COPY . . RUN npm run buildReplace
<service-id>with the actual Railway service ID as required by Railway's cache-mount format. If the final image needs production dependencies, create them in a clean final stage withnpm ci --omit=dev; do not overlay a cachednode_modulesdirectory or copy host dependencies into it. -
Keep exactly one lockfile for the selected package manager and use its clean-install command (
npm ci,pnpm install --frozen-lockfile, or the equivalent). Mixing npm/yarn/pnpm layouts can recreate the file-versus-directory collision even after the server cache is bypassed.
Interpret the result:
- If the no-cache build succeeds, the old cache mount was the fault. Keep the new package-store cache target, remove
NO_CACHE=1, and run one more build to prove the clean cache is reusable. - If the same path fails with
NO_CACHE=1, the collision is in the source/build stages rather than Railway's stored cache. Inspect the line immediately before the error for aCOPYinto/app/node_modules, a committed dependency/symlink, or a second package-manager install; removing that overlay is the fix. - If a no-cache build still references the old cache-mount ID even after the Dockerfile no longer mounts
/app/node_modules, send Railway the deployment ID, service ID, builder type and the failing cache-mount path so staff can delete that exact orphaned mount. Do not recreate the service or delete a healthy deployment first.
Official references: