Client-side fetch paths resolve to server routes
Why it matters
A client that fetches /api/user/profile when the server only defines /api/users/me returns 404 on every call in production — and AI tools are specifically prone to inventing plausible-sounding endpoints that do not exist. The user sees a loading spinner that never resolves, or a silent data-load failure that reads as a blank page. This is reference-integrity at the API boundary and it aligns directly with OWASP A05 (Security Misconfiguration) when the 404 exposes stack traces.
Severity rationale
Critical because a broken fetch URL produces a user-visible 404 on every call and silently corrupts every page that depends on the data.
Remediation
For each unresolved URL, either create the missing route handler or correct the client specifier. In Next.js App Router, the handler lives next to the URL path in app/api/...:
// app/api/user/profile/route.ts
export async function GET() {
return Response.json({ /* ... */ })
}
If you route through next.config.* rewrites, verify the rewrite source matches the fetch specifier exactly.
Detection
-
ID:
client-fetch-paths-resolve -
Severity:
critical -
What to look for: Walk source files for calls to
fetch(...),axios.get/post/put/patch/delete/request(...),ky.get/post/put/patch/delete(...),useSWR("..."),useQuery({ queryFn: ... fetch("...") }),mutate("..."). Extract the first argument string literal. SKIP any URL with a scheme (http://,https://,ws://,wss://) — these are external API calls. SKIPmailto:,tel:,data:URIs. For the remaining relative URLs starting with/, normalize dynamic segments by converting Next.js[param]↔ Express:param↔ template literal${var}↔ OpenAPI{param}to a canonical placeholder (e.g.,:PARAM). Match against the project's API route tree from theAPI_ROUTESmap built in the analysis step. Count all relative fetch URLs inspected, total resolved, total unresolved. Sample at most 100 unique URLs and report the sample size. -
Pass criteria: 100% of relative fetch URLs resolve to an existing server route file. Report: "X unique relative fetch URLs inspected, Y resolved, 0 unresolved."
-
Fail criteria: At least 1 relative fetch URL does not resolve to a server route file after dynamic-segment normalization.
-
Do NOT pass when: A fetch URL is constructed at runtime from a variable (
fetch(/api/users/${id})) but the base path/api/users/[id]route does not exist — runtime construction does not exempt the base path from resolution. -
Skip (N/A) when: Project has no API routes detected (no
app/api/, nopages/api/, noroutes/, noserver/) AND nonext.config.*rewrites referencing/api/*paths. -
Cross-reference: For broader API contract analysis, the API Design audit (
api-design) covers endpoint design quality. -
Detail on fail:
"4 unresolved fetch URLs: '/api/user/profile' in src/components/UserCard.tsx (no matching route file under app/api/user/), '/api/posts/[id]/comments' in src/hooks/useComments.ts (route file missing). Sampled 47 of 47 unique fetch URLs." -
Remediation: A fetch to a non-existent route returns 404 in production — and AI tools love to hallucinate plausible-looking API endpoints. Fix each unresolved URL:
// Either create the missing route file // app/api/user/profile/route.ts export async function GET() { return Response.json({ /* ... */ }) } // Or fix the fetch call to point at an existing route fetch('/api/users/me') // existing routeIf you use a Next.js rewrites config or an API gateway, the check normalizes through
next.config.*rewrites — make sure rewrites are declared.
External references
- owasp:2021 · A05 — Security Misconfiguration
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-hallucinations·automated