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

  1. Fix the import to match the module's actual export (named vs default)
  2. Ensure options.handler is the function itself, not a string reference or an instance
  3. Validate before startup: if (typeof handler !== 'function') throw ...
  4. 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

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


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/045666d39ff182b1. Report an issue: GitHub.