{"record":{"id":"045666d39ff182b1","repo":"denoland/deno","slug":"cannot-serve-http-requests-handler-must-be-a-func","errorCode":null,"errorMessage":"Cannot serve HTTP requests: handler must be a function, received ${typeof handler}","messagePattern":"Cannot serve HTTP requests: handler must be a function, received (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/00_serve.ts","lineNumber":1180,"sourceCode":"\n  if (typeof arg1 === \"function\") {\n    handler = arg1;\n  } else if (typeof arg2 === \"function\") {\n    handler = arg2;\n    options = arg1;\n  } else {\n    options = arg1;\n  }\n  if (handler === undefined) {\n    if (options === undefined) {\n      throw new TypeError(\n        \"Cannot serve HTTP requests: either a `handler` or `options` must be specified\",\n      );\n    }\n    handler = options.handler;\n  }\n  if (typeof handler !== \"function\") {\n    throw new TypeError(\n      `Cannot serve HTTP requests: handler must be a function, received ${typeof handler}`,\n    );\n  }\n  if (options === undefined) {\n    options = { __proto__: null };\n  }\n\n  if (serveAddressOverrideConsumed) {\n    return serveInner(options, handler);\n  }\n\n  const {\n    0: overrideKind,\n    1: overrideHost,\n    2: overridePort,\n    3: duplicateListener,\n  } = op_http_serve_address_override();\n  if (overrideKind) {","sourceCodeStart":1162,"sourceCodeEnd":1198,"githubUrl":"https://github.com/denoland/deno/blob/abd22074e47c6a5cd14e9e4e84743f084aa5a575/ext/http/00_serve.ts#L1162-L1198","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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).","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"],"exampleFix":"// before\nDeno.serve({ port: 8000, handlers: app }); // typo -> received undefined\n\n// after\nDeno.serve({ port: 8000, handler: app });","handlingStrategy":"validation","validationCode":"// Validate the options shape before starting the server:\nfunction assertServeOptions(opts: Record<string, unknown>) {\n  if (typeof opts.handler !== 'function') {\n    throw new Error(`serve options: expected handler function, got ${typeof opts.handler}`);\n  }\n}\nassertServeOptions(config); // before Deno.serve(config)","typeGuard":"const hasValidHandler = (o: unknown): o is { handler: Deno.ServeHandler } =>\n  typeof o === 'object' && o !== null && typeof (o as { handler?: unknown }).handler === 'function';","tryCatchPattern":null,"preventionTips":["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"],"tags":["http","deno-serve","api-misuse","startup","validation"],"backgroundTag":"invalid-handler-type","analyzedSha":"abd22074e47c6a5cd14e9e4e84743f084aa5a575","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}