denoland/deno · error · TypeError
Cannot serve HTTP requests: either a `handler` or `options`…
Error message
Cannot serve HTTP requests: either a `handler` or `options` must be specified
What it means
Deno.serve's argument parser accepts `serve(handler)`, `serve(options, handler)`, or `serve(optionsWithHandler)`; if none of the arguments is a function, `options` must exist and carry a `handler`. This TypeError fires when serve is called with no usable arguments at all — typically `Deno.serve()` or `Deno.serve(undefined)`. It is a startup-time configuration error, thrown synchronously before any listener is created.
Solutions
- Pass a handler function: `Deno.serve(handler)` or `Deno.serve({ port: 8000, handler })`
- If building options dynamically, fall back to a concrete options object: `Deno.serve(opts ?? { port: 8000, handler })`
- Check for undefined before calling when handlers come from dynamic imports
Example fix
// before
Deno.serve(); // no handler, no options
// after
Deno.serve({ port: 8000, handler: (req) => new Response('ok') }); Defensive patterns
Strategy: validation
Validate before calling
// Verify arguments before calling serve:
const handler: Deno.ServeHandler | undefined = resolveHandler();
if (typeof handler !== 'function') {
throw new Error('Deno.serve: no handler resolved — check dynamic imports');
}
Deno.serve({ port: 8000 }, handler); Type guard
const isServeHandler = (v: unknown): v is Deno.ServeHandler => typeof v === 'function';
Prevention
- Always pass either a function or an options object containing handler
- Fail fast on undefined handlers from dynamic imports instead of forwarding them
- Keep serve() calls in one place so the contract is easy to review
When it happens
Trigger: Calling `Deno.serve()` with zero arguments while wiring code up, passing an undefined variable as the only argument (`Deno.serve(missingHandler)` where the import failed silently), or passing a non-function first argument and a non-function second argument so options stays undefined.
Common situations: Scaffolding/boilerplate run before the handler is written, circular imports yielding undefined handlers, dynamic construction of the serve arguments from config that produced nothing.
Related errors
- Cannot serve HTTP requests: handler must be a function…
- 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/7cc789d83f2b6729.
Report an issue: GitHub.
Appendix: source
Thrown at ext/http/00_serve.ts:1173
// Flag to track if DENO_SERVE_ADDRESS override has been consumed
let serveAddressOverrideConsumed = false;
function serve(arg1, arg2) {
let options: RawServeOptions | undefined;
let handler: RawHandler | undefined;
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);
}
View on GitHub (pinned to abd22074e4)