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

  1. Use `Deno.serve({ port, handler })` with handler spelled exactly and set to a function
  2. If you prefer positional form, put the function first: `Deno.serve(handler)` or `Deno.serve(options, handler)`
  3. 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

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


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)