denoland/deno · error · TypeError
Cannot serve HTTP requests: handler must be a function, rece
Error message
Cannot serve HTTP requests: handler must be a function, received ${typeof handler} What it means
After argument parsing resolves the handler (function argument, second argument, or options.handler), serve verifies it is actually a function and throws this TypeError, including the received typeof, when it is not. This is the guard behind the previous 'either a handler or options' check and fires when a handler key exists but holds a non-function value.
Source
Thrown at ext/http/00_serve.ts:1157
if (typeof arg1 === "function") {
handler = arg1;
} else if (typeof arg2 === "function") {
handler = arg2;
options = arg1;
} else {
options = arg1;
}
if (handler === undefined) {
if (options === undefined) {
throw new TypeError(
"Cannot serve HTTP requests: either a `handler` or `options` must be specified",
);
}
handler = options.handler;
}
if (typeof handler !== "function") {
throw new TypeError(
`Cannot serve HTTP requests: handler must be a function, received ${typeof handler}`,
);
}
if (options === undefined) {
options = { __proto__: null };
}
if (serveAddressOverrideConsumed) {
return serveInner(options, handler);
}
const {
0: overrideKind,
1: overrideHost,
2: overridePort,
3: duplicateListener,
} = op_http_serve_address_override();
if (overrideKind) {View on GitHub (pinned to 89f33cbef2)
Solutions
- Fix the import to match the module's actual export (named vs default)
- Ensure options.handler is the function itself, not a string reference or an instance
- Validate before startup: if (typeof handler !== 'function') throw ...
- Check the error message's typeof value to identify what was actually passed
Example fix
// before
import handler from "./router.js"; // router.js only exports `handler` named
Deno.serve({ port: 8000, handler }); // handler is undefined
// after
import { handler } from "./router.js";
Deno.serve({ port: 8000, handler }); Defensive patterns
Strategy: validation
Validate before calling
// Guard dynamic handler wiring before startup
if (typeof options.handler !== "function") {
throw new TypeError(`handler must be a function, got ${typeof options.handler}`);
}
Deno.serve(options); Type guard
function isHandler(v) {
return typeof v === "function";
} Prevention
- Verify imports: a missing default export yields undefined silently in JS
- Use `import { handler } from ...` matching the module's actual export style
- Log typeof handler right before serve() when wiring routes dynamically
When it happens
Trigger: options.handler being undefined because a default import has no matching export; handler: 'handleRequest' as a string; handler: someObject because a factory call was forgotten; handler: null after conditional wiring.
Common situations: Bad imports (default vs named export mismatches), DI containers or route registries that resolve the handler to undefined, and refactors that turn the handler function into an object.
Related errors
- Cannot serve HTTP requests: either a `handler` or `options`
- Already upgraded
- Already closed
- Request closed
- Invalid response
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/045666d39ff182b1.
Report an issue: GitHub.