# Client-side fetch paths resolve to server routes

- **Pattern:** `ab-000027` (`ai-slop-hallucinations.route-references.client-fetch-paths-resolve`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000027
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000027)

## 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/...`:

```ts
// 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. SKIP `mailto:`, `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 the `API_ROUTES` map 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/`, no `pages/api/`, no `routes/`, no `server/`) AND no `next.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:

  ```ts
  // 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 route
  ```

  If 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 A05

Taxons: reference-integrity

HTML version: https://auditbuffet.com/patterns/ab-000027
