a month ago
Problem
Since 23 Aug (AEST), every build of this repo fails during npm run build with:
./src/app/dashboard/fault-library/page.tsx
Module not found: Can't resolve '@/lib/electricalSafetyCheck'
./src/app/dashboard/reports/electrical-safety-check/[id]/page.tsx
Module not found: Can't resolve '@/components/SignaturePad'
Module not found: Can't resolve '@/components/PhotoField'
Module not found: Can't resolve '@/components/ResultButtons'
Module not found: Can't resolve '@/components/FaultsPanel'
All five files exist at the commit being built.
What we've verified
The same commit (git checkout origin/main; rm -rf .next node_modules; npm ci; npm run build) builds successfully locally.
git ls-tree -r HEAD shows all five files tracked as regular files (mode 100644) at exactly the imported paths; import strings match stored paths byte-for-byte (case-sensitive check done).
No .gitattributes exists (no export-ignore); git archive HEAD includes all five files.
tsconfig.json paths: "@/": ["./src/"].
No .dockerignore/.railwayignore; no root directory, custom build command, watch paths, or volumes on the service.
Reproduced with NO_CACHE=1 (log confirms "No build cache found") — same failure.
Created a brand-new service from the same repo/branch: identical failure on its first build.
The failure is selective: all other @/… imports across the app resolve; only these five modules fail.
Also possibly relevant
Failed deployments in the dashboard show 8-char IDs (e.g. c3dc8d7f, 98e64166) that do not correspond to any git SHA in the repository, so we can't confirm which snapshot was built.
Railway Agent was used on this service earlier the same day and created two PRs/branches (railway/code-change-XJJDu-…, railway/fix-deploy-b31ce8).
The currently Active deployment (from 12 Aug, a49f4199) predates these files and runs fine.
3 Replies
a month ago
This thread has been opened as a bounty so the community can help solve it.
Status changed to Open Railway • about 1 month ago
a month ago
This looks like a source-snapshot issue rather than Next.js resolution. The important test is to print git rev-parse HEAD and ls -la for those five files from inside the Railway build. If the SHA/files there differ from the GitHub commit you verified, Railway is building a different snapshot. The 8-character IDs in the Railway dashboard are deployment IDs, not Git SHAs, so they shouldn't be used to identify the source commit.
Given that a fresh service, NO_CACHE=1, and a clean local clone all reproduce/resolve differently, I'd verify the exact commit Railway is building before changing any Next.js or TypeScript configuration.
a month ago
Agree the 8-char IDs are deployment IDs and not SHAs, but I don't think Railway's building the wrong snapshot here. I think it's building the right one and the local check is what's off.
Two things in your repro don't do what they look like they do.
rm -rf .next node_modules isn't a clean tree. It nukes build output and deps, but untracked files stay exactly where they are, and git checkout origin/main won't touch them either. So if those five files were never actually committed to main, your local build picks them up off disk and passes. Railway clones main fresh and they're just not there.
Second, git ls-tree -r HEAD is telling you about HEAD, not about whatever ref the service actually deploys. If HEAD sat on one of those railway/code-change-... branches at any point, it'll cheerfully list all five at 100644 while origin/main has none of them.
That would explain the selectivity, which is the part that makes this look impossible otherwise. The errors are being raised from fault-library/page.tsx and reports/electrical-safety-check/[id]/page.tsx, so those two pages are definitely in the build. If Railway were on some older snapshot it'd be missing the pages too and you'd get nothing out of them at all. What you've got is a tree with the importers but not the imports, which is what a half-committed change looks like.
The Railway Agent thing you mentioned lines up with that too. If it wrote those five on railway/code-change-XJJDu and the PR never got merged, they're in git history, they show up in ls-tree on that branch, and main still doesn't have them.
You should chck against the deployed branch rather than HEAD:
git fetch origin --prune
git ls-tree -r origin/main --name-only | grep -E 'electricalSafetyCheck|SignaturePad|PhotoField|ResultButtons|FaultsPanel'
Under five lines and you're done, nothing to change in next.config or tsconfig.
If they are missing, these tell you where they went:
git status --porcelain -uall | grep -E 'electricalSafetyCheck|SignaturePad|PhotoField|ResultButtons|FaultsPanel'
git log --all --oneline -- src/components/SignaturePad.tsx
git check-ignore -v src/lib/electricalSafetyCheck.ts src/components/SignaturePad.tsx src/components/PhotoField.tsx src/components/ResultButtons.tsx src/components/FaultsPanel.tsx
?? on the first one means never committed. The log shows which branch they landed on. Run check-ignore even if you're sure your gitignore is fine, a stray lib/ or /components rule from whatever template the repo started from will drop new files silently and git add . won't complain about it.
For a local repro you can actually trust, clone somewhere fresh instead of reusing your working copy:
git clone --branch main /tmp/verify && cd /tmp/verify && npm ci && npm run build
If that breaks the same way, the snapshot was never the problem.
One thing on printing git rev-parse HEAD from inside the build, that won't work. Railway builds from an uploaded source snapshot, so there's no .git in the build container. Use the env var:
echo "$RAILWAY_GIT_COMMIT_SHA on $RAILWAY_GIT_BRANCH" && ls -la src/lib src/components && npm run build
Drop that in as the build command temporarily and you get the commit and the real directory contents in one go.
If it is what I think it is, the fix is just getting the files onto main. Merge the agent's PR if that's where they ended up, or git add -f them and fix the ignore rule.
a month ago
Hey, we got to the bottom of it, turns out it wasn't the snapshot at all, it was devDependencies not being installed in the build.
typescript was sitting in devDependencies, and Next.js reads the paths config in tsconfig.json through the installed typescript package. With typescript missing from the container, the @/* alias never got created — no error, no warning, the alias just didn't exist — so every @/ import failed to resolve. tailwindcss, postcss and autoprefixer were the same problem one layer down; they only showed up after the alias was fixed and the build got far enough to hit the CSS.
The reason it looked like a snapshot issue is that webpack reports a failed module request against a single importer, so a total alias failure printed as exactly five "Module not found" errors — and those five happened to be the newest files in the repo, which made it look exactly like a half-committed feature. And local builds kept passing because plain npm ci installs devDependencies. Running npm ci --omit=dev locally reproduced the Railway failure straight away.
Your build command suggestion with RAILWAY_GIT_COMMIT_SHA and ls -la was the turning point, it proved the snapshot had all the files intact, which forced us to stop looking at the source and start looking at the environment. Appreciate that one.
The fix: moved typescript, tailwindcss, postcss, autoprefixer and the @types packages into dependencies, regenerated the lockfile, and added an explicit resolve.alias for @/ in next.config.js so the alias doesn't depend on typescript being installed at all. Both services are building green now.
