Cannot GET / (Express / Node no matching route)

Express answered the HTTP request, but no route matched that method and path. The server is up — the URL is wrong or unregistered.

How it shows up

Cannot GET /
Cannot GET /api/users
Cannot POST /login

HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
X-Powered-By: Express

You are past connect/TLS. curl gets a real HTTP response — just not the handler you expected.

What Express is saying

After the middleware stack runs, if nothing called res.send / next into a final handler, Express’s final handler sends a tiny HTML body: Cannot METHOD path. NestJS, some Fastify setups, and older Connect apps can print the same style of message.

vs lookalikes

SymptomMeans
Cannot GET /App up; no route for that method+path (404)
localhost refused to connectNothing listening on the port
EADDRINUSEYour new process could not bind; old one may still be the one answering
502 Bad GatewayProxy could not get a valid reply from upstream
503 / 504Unavailable or gateway timeout — not a missing route
Blank SPA page / client router onlyServer needs a fallback to index.html for client-side routes

Common causes

Minimal fix patterns

import express from "express";
const app = express();

app.get("/", (_req, res) => res.send("ok"));
app.get("/api/health", (_req, res) => res.json({ ok: true }));

// JSON 404 instead of "Cannot GET …"
app.use((req, res) => {
  res.status(404).json({ error: "not_found", path: req.path, method: req.method });
});

app.listen(3000, "127.0.0.1");
# Confirm what answers
curl -sI http://127.0.0.1:3000/
curl -s http://127.0.0.1:3000/missing
# List listeners if the wrong app might be up
ss -ltnp | grep 3000

SPA fallback (careful order)

app.use(express.static("dist"));
app.get("*", (req, res, next) => {
  if (req.path.startsWith("/api")) return next();
  res.sendFile("index.html", { root: "dist" });
});
// then API 404 / error handlers

Put API routes before the * fallback so /api/… still 404s as JSON when missing.

Checklist

  1. Log req.method + req.originalUrl on a catch-all to see what arrived (proxy prefixes included).
  2. Verify the router is mounted: app.use('/api', apiRouter).
  3. Match method and path exactly; trailing slashes matter unless you normalize them.
  4. Replace the default HTML 404 with JSON for APIs.
  5. If curl to the port works but the public URL 404s, fix the reverse-proxy location / proxy_pass path.

Related

Invalid hook call (React) · localhost refused to connect · EADDRINUSE address already in use · 502 Bad Gateway · TypeError: Failed to fetch · CORS errors explained · Anvil HTTP status · Anvil URL inspect

Questions

What does Cannot GET / mean in Express?

Express received the request but no route matched that GET path, so it returned its default 404 HTML body.

Is the server down?

Usually no. Connection refused means down/wrong port. Cannot GET means the process answered with 404.

Why Cannot GET /api when my route exists?

Mount path, typo, trailing slash, wrong method (GET vs POST), or a reverse proxy rewriting the path differently than the app expects.

How do I change Cannot GET to JSON?

Add a final middleware that does res.status(404).json({ error: 'not_found' }) after all real routes.

Does this happen only in Express?

The exact phrase is classic Express, but any framework that returns a plain-text/HTML 404 for unknown routes can look similar.

Cannot GET on a React/Vue refresh?

Client-side routers need a server fallback to index.html for non-API paths; otherwise Express correctly says the file/route does not exist.

Published .

Try it

Related guides

Newest guides