denoland/deno · error · TypeError
Cannot serve HTTP requests: handler must be a function…
Error message
Cannot serve HTTP requests: handler must be a function, received ${typeof handler} What it means
After argument parsing, Deno.serve verifies the resolved handler is callable; this TypeError reports the actual typeof received. It fires when options exist but `options.handler` is missing (received undefined) or is a non-function (string, object, number), or when the first argument is a non-function and no second function argument rescues it. Startup fails synchronously; no listener is created.
Solutions
- Use `Deno.serve({ port, handler })` with handler spelled exactly and set to a function
- If you prefer positional form, put the function first: `Deno.serve(handler)` or `Deno.serve(options, handler)`
- Log `typeof handler` before calling serve when wiring handlers dynamically
Example fix
// before
Deno.serve({ port: 8000, handlers: app }); // typo -> received undefined
// after
Deno.serve({ port: 8000, handler: app }); Defensive patterns
Strategy: validation
Validate before calling
// Validate the options shape before starting the server:
function assertServeOptions(opts: Record<string, unknown>) {
if (typeof opts.handler !== 'function') {
throw new Error(`serve options: expected handler function, got ${typeof opts.handler}`);
}
}
assertServeOptions(config); // before Deno.serve(config) Type guard
const hasValidHandler = (o: unknown): o is { handler: Deno.ServeHandler } =>
typeof o === 'object' && o !== null && typeof (o as { handler?: unknown }).handler === 'function'; Prevention
- Spell the key exactly `handler` (not handlers/handle)
- Remember positional order: serve(handler) or serve(options, handler) — never serve(handler, options)
- Type the options object as Deno.ServeInit so TS catches missing handlers
When it happens
Trigger: `Deno.serve({ port: 8000 })` with no handler property (received undefined), `handler` misspelled (`handlers: fn`), `options.handler` set to a class instance or string route table, or argument order swapped so the function lands in a spot the parser ignores.
Common situations: Typos in the options key, config-driven server setup where the handler failed to attach, mixing up `serve(handler, options)` (invalid) with `serve(options, handler)` (valid).
Related errors
- Cannot serve HTTP requests: either a `handler` or `options`…
- Both 'cert' and 'key' must be provided to enable HTTPS
- Return value from onError handler must be a response or a…
- Return value from serve handler must be a response or a…
- ERR_HTTP_INVALID_HEADER_VALUE
AI-assisted analysis of denoland/deno@abd22074e4 (2026-08-20).
Data as JSON: /api/errors/045666d39ff182b1.
Report an issue: GitHub.
Appendix: source
Thrown at ext/http/00_serve.ts:1180
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 abd22074e4)