Path alias imports resolve to actual files
Why it matters
Path-alias hallucinations are one of the most common AI failure modes: the model writes import { calculateTax } from '@/lib/billing/calculator' for a file it imagined rather than a file that exists. The TypeScript compiler and the bundler both fail at the resolution step, so the build breaks and the route cannot render. Even when tsc --noEmit is skipped in CI, runtime imports via dynamic import() throw Cannot find module the first time the code path executes in production.
Severity rationale
High because an unresolved alias breaks the build or crashes the route at runtime, though a passing `tsc` step catches it before deploy.
Remediation
Run tsc --noEmit to surface every unresolved alias, then for each one decide whether to create the missing file or correct the import specifier. Fix the reference in place:
// Correct: points at a file that actually exists under src/lib/billing/
import { calculateTax } from '@/lib/billing/tax'
If the alias itself is wrong, update tsconfig.json compilerOptions.paths so the prefix maps to the real directory.
Detection
-
ID:
path-aliases-resolve -
Severity:
high -
What to look for: Read
tsconfig.jsonand anytsconfig.*.jsonfiles. ExtractcompilerOptions.pathsto build the alias map (e.g.,"@/*": ["./src/*"]). For every import in source files whose specifier matches an alias prefix, resolve the alias to the target directory and verify the resolved path points to an actual file. Apply standard extension resolution: try.ts,.tsx,.js,.jsx,.mjs,.cjs, then tryindex.ts,index.tsx,index.js,index.jsxif the resolved path is a directory. Count all alias imports inspected, total resolved, total unresolved. -
Detector snippet (Node-capable tools only): If the tool has a shell with Node available, parse
tsconfig.jsonpaths, scan every source file for imports matching an alias prefix, and resolve each target against the filesystem. Output reports the total alias imports and the count + identity of the unresolved ones. If exit 0 with "unresolved=0", report pass. If "unresolved>0", report fail with count. Exit >=2 or command not found — fall back to prose reasoning below.node -e 'const fs=require("fs"),path=require("path");const ts=JSON.parse(fs.readFileSync("tsconfig.json","utf-8"));const paths=(ts.compilerOptions&&ts.compilerOptions.paths)||{};const base=(ts.compilerOptions&&ts.compilerOptions.baseUrl)||".";function w(d,o=[]){try{for(const e of fs.readdirSync(d,{withFileTypes:true})){if(e.name==="node_modules"||e.name===".next")continue;const p=path.join(d,e.name);e.isDirectory()?w(p,o):o.push(p)}}catch{}return o}let t=0,u=[];for(const f of w("src")){if(!/\.(ts|tsx|js|jsx|mjs)$/.test(f))continue;const s=fs.readFileSync(f,"utf-8"),imp=[...s.matchAll(/from\s+[\u0022\u0027]([^\u0022\u0027]+)[\u0022\u0027]/g)].map(m=>m[1]);for(const i of imp){for(const [k,vs] of Object.entries(paths)){const pre=k.replace(/\*$/,"");if(!i.startsWith(pre))continue;t++;const rest=i.slice(pre.length);let ok=false;for(const v of vs){const rp=path.resolve(base,v.replace(/\*$/,rest));for(const ext of ["",".ts",".tsx",".js",".jsx","/index.ts","/index.tsx"]){if(fs.existsSync(rp+ext)){ok=true;break}}if(ok)break}if(!ok)u.push(f+": "+i);break}}}console.log("total="+t+" unresolved="+u.length);u.slice(0,3).forEach(x=>console.log(x))' -
Pass criteria: 100% of alias-prefixed imports resolve to an existing file (with extension) or directory containing an
indexfile. Report: "X alias imports inspected, Y resolved, 0 unresolved." -
Fail criteria: At least 1 alias-prefixed import resolves to a non-existent path after extension resolution.
-
Do NOT pass when: The alias map is empty but imports use alias-style paths (
@/lib/foowith no@/*alias defined) — those should be flagged as unresolved. -
Skip (N/A) when:
tsconfig.jsondoes not exist ORtsconfig.jsondoes not definecompilerOptions.paths. -
Report even on pass: Always report the count. Example: "147 alias imports inspected (alias prefixes: '@/', '~/'), 147 resolved (100%)."
-
Detail on fail:
"5 alias imports do not resolve: '@/lib/billing/calculator' in src/app/checkout/page.tsx, '@/components/MissingDialog' in src/app/page.tsx (file not found in src/components/)" -
Remediation: Path alias hallucinations are a top AI failure mode — the model imagines a
@/lib/utilshelper that doesn't exist. Fix each unresolved alias import:// Bad: AI imagined this file import { calculateTax } from '@/lib/billing/calculator' // Good: import from a file that actually exists, or create the file import { calculateTax } from '@/lib/billing/tax'Run
tsc --noEmitto surface module-resolution errors at build time. If a file should exist, create it. If the import was wrong, fix the path. If the alias is misconfigured, updatetsconfig.jsoncompilerOptions.paths.
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-hallucinations·automated
- 2026-04-20·v1.1.0·Add Phase 6.1 detect-node snippet for deterministic path-alias resolution·by cakleinman