{"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":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/00_serve.ts","lineNumber":1157,"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":1139,"sourceCodeEnd":1175,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/http/00_serve.ts#L1139-L1175","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fix the import to match the module's actual export (named vs default)","Ensure options.handler is the function itself, not a string reference or an instance","Validate before startup: if (typeof handler !== 'function') throw ...","Check the error message's typeof value to identify what was actually passed"],"exampleFix":"// before\nimport handler from \"./router.js\"; // router.js only exports `handler` named\nDeno.serve({ port: 8000, handler }); // handler is undefined\n\n// after\nimport { handler } from \"./router.js\";\nDeno.serve({ port: 8000, handler });","handlingStrategy":"validation","validationCode":"// Guard dynamic handler wiring before startup\nif (typeof options.handler !== \"function\") {\n  throw new TypeError(`handler must be a function, got ${typeof options.handler}`);\n}\nDeno.serve(options);","typeGuard":"function isHandler(v) {\n  return typeof v === \"function\";\n}","tryCatchPattern":null,"preventionTips":["Verify imports: a missing default export yields undefined silently in JS","Use `import { handler } from ...` matching the module's actual export style","Log typeof handler right before serve() when wiring routes dynamically"],"tags":["http","serve","api-misuse","imports","configuration"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}