Diagnosing tRPC useQuery 404 Errors: A Step‑by‑Step Guide
When tRPC useQuery returns a 404 or null, the problem is often a missing or mis‑named route. Follow this diagnostic flow to pinpoint the route, verify network traffic, and resolve the issue quickly.
15 May 2026, 23:19 UTC

Problem Statement
In a tRPC‑powered React app, the useQuery hook sometimes resolves with a TRPCClientError that contains a 404 status or returns null without any data. The underlying cause is usually that the client request never reaches a matching route on the server.
Typical Symptom
- React component renders
Loading...thenNot foundorUnknown error - Network tab shows a
404 Not Foundresponse for the tRPC endpoint URL - Server logs show no handler execution for the requested procedure
Common Causes
- Route omitted or misspelled in the server‑side router file.
- Incorrect import path or alias that prevents the router from being registered.
- Middleware placed before the router that short‑circuits the request.
- Client query key or procedure name mismatched with the server definition.
- Server‑side helpers not passed to the client during SSR, causing the client to call a non‑existent route.
- Using an older tRPC version (
v4) where error objects differ fromv5.
Diagnostic Flow
Follow the ordered checks below. Stop at the first failing step and apply the corresponding fix before moving on.
- Verify the router file
- Open the file that declares your server‑side procedures (e.g.,
src/server/router.ts). - Confirm the procedure name exactly matches the one used on the client (case‑sensitive).
- Example: If the client calls
ctx.query('user.getProfile'), the router must containuser.getProfile.
- Open the file that declares your server‑side procedures (e.g.,
- Check the import path
- Ensure the router is exported and imported in the server entry point (e.g.,
src/server/index.ts). A wrong alias can result in the router never being registered. - Look for console warnings about “handler not found” when the server starts.
- Ensure the router is exported and imported in the server entry point (e.g.,
- Inspect middleware order
- Middleware that runs before the router can return a response or throw an error, preventing the route from executing.
- Verify that
appRouteris passed after any custom middleware in the tRPC middleware chain.
- Confirm the query key
- In the client,
useQuery(['user.getProfile'], { … })must match the server route name. - Any typo or extra namespace will cause a 404.
- In the client,
- Network tab check
- Open DevTools, go to the Network tab, and trigger the query.
- Verify the request URL ends with
/trpc/user.getProfileand the response status is404(or200with empty payload).
- SSR helper verification
- If using
createServerSideHelpers, ensure it is passed to thetrpcprovider on the client side. - Missing helpers can result in the client falling back to a client‑only router that lacks the procedure.
- If using
- Version check
- Run
npm list @trpc/server @trpc/clientto confirm you are onv5(or the version you expect). - Older versions use
TRPCErrorwith different properties; adjust your error handling accordingly.
- Run
Fixes Tied to Findings
| Finding | Fix |
|---|---|
| Route missing or misspelled | Add the missing procedure to the router or correct the name. |
| Wrong import path | Correct the import alias or path so the router is exported to the server entry point. |
| Middleware short‑circuits | Reorder middleware so the router is reached, or modify the middleware to call next(). |
| Query key mismatch | Update the useQuery key to match the server route. |
| SSR helpers missing | Pass the helpers to the trpc provider: trpc.Provider value={helpers}. |
| Wrong tRPC version | Upgrade to a compatible version or adjust error handling to match the version’s API. |
Concrete Example
Suppose the client calls:
const { data, error } = trpc.user.getProfile.useQuery({ userId: 42 });
but the server router contains:
export const appRouter = router({
user: router({
getUser: publicProcedure.input(z.number()).query(({ input }) => {
// fetch user
}),
}),
});
Because the procedure is named getUser instead of getProfile, the client receives a 404. Renaming the server procedure or updating the client call resolves the issue.
Escalation Criteria
- If all diagnostic steps pass but the query still fails, consider checking for network proxy or CORS issues that might modify the request path.
- Review the server logs for any unexpected errors that could be swallowed by middleware.
- Ask for a peer review of the router and middleware configuration if the problem persists.
Verification Checklist
- Network tab shows
200with valid JSON payload. - Server logs confirm the procedure ran (e.g., console.log inside the query).
- Component renders the expected data without error.
- Re‑run the test suite to ensure no regressions.
Limitations
This guide assumes a standard tRPC setup with @trpc/server and @trpc/client v5. Custom middleware, advanced type inference tricks, or non‑standard routing patterns may require additional investigation.
Practical Takeaway
When useQuery returns a 404, the most common culprit is a mismatch between the client key and the server router. Validate the router, imports, middleware order, and SSR helpers in that order, apply the specific fix, and confirm the change by inspecting the network and server logs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.