{"record":{"id":"8e5eaf2c1f664f4e","repo":"denoland/deno","slug":"invalid-type-for-fetch-must-be-a-function","errorCode":null,"errorMessage":"Invalid type for fetch: must be a function","messagePattern":"Invalid type for fetch: must be a function","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/00_serve.ts","lineNumber":1640,"sourceCode":"    },\n    [SymbolAsyncDispose]() {\n      return this.shutdown();\n    },\n  };\n}\n\ninternals.addTrailers = addTrailers;\ninternals.serveHttpOnListener = serveHttpOnListener;\ninternals.serveHttpOnConnection = serveHttpOnConnection;\ninternals.resetLegacyAbortWarning = () => {\n  legacyAbortWarned = false;\n};\n\nfunction registerDeclarativeServer(exports) {\n  if (!ObjectHasOwn(exports, \"fetch\")) return;\n\n  if (typeof exports.fetch !== \"function\") {\n    throw new TypeError(\"Invalid type for fetch: must be a function\");\n  }\n\n  if (\n    exports.onListen !== undefined && typeof exports.onListen !== \"function\"\n  ) {\n    throw new TypeError(\"Invalid type for onListen: must be a function\");\n  }\n\n  return ({\n    servePort,\n    serveHost,\n    workerCountWhenMain,\n  }) => {\n    const server = Deno.serve({\n      port: servePort,\n      hostname: serveHost,\n      [kLoadBalanced]: workerCountWhenMain == null\n        ? true","sourceCodeStart":1622,"sourceCodeEnd":1658,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/http/00_serve.ts#L1622-L1658","documentation":"Thrown by Deno's declarative server registration (registerDeclarativeServer), which runs when a module exports a top-level 'fetch' export (the module-as-server style used by 'deno serve' and deploy-style entrypoints). If the exports object has an own property 'fetch', that value must be a function; anything else (a number, string, object, class instance) is rejected before Deno.serve is created.","triggerScenarios":"A main/entry module run via 'deno serve' (or a worker spawned for it) whose default or named export object contains fetch: 42, fetch: 'handler', or fetch bound to a non-callable; accidentally exporting a variable named fetch that shadows the global fetch builtin; export const fetch = someObject.handler missing the .bind.","commonSituations":"Naming a data field or constant 'fetch' in a module that is also used as a serve entrypoint; refactoring a Request handler into a config object and exporting the object; copy-pasting deploy example code into a module that already exports an unrelated fetch symbol.","solutions":["Make the exported fetch a function: export const fetch = (req: Request) => new Response('ok'); or export default { fetch(req) { ... } }.","If 'fetch' is not meant to be a server handler, rename the export (e.g. fetchConfig) so the module does not look like a declarative server.","Run the file with 'deno run' plus an explicit Deno.serve(handler) call instead of relying on the export-based convention."],"exampleFix":"// before\nexport const fetch = { handler: (req) => new Response(\"hi\") }; // object, not callable\n\n// after\nexport default {\n  fetch(req: Request) {\n    return new Response(\"hi\");\n  },\n};","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"type ServeExports = { fetch?: (req: Request, info: { remoteAddr; url }) => Response | Promise<Response>; onListen?: (info: { hostname: string; port: number }) => void };\nfunction isValidServeModule(m: ServeExports): boolean { return typeof m.fetch !== \"function\" ? false : true; }","tryCatchPattern":null,"preventionTips":["Type entrypoint exports explicitly instead of relying on inference.","Never name non-handler exports 'fetch' in serve entrypoints.","Run `deno check` on the entry module in CI to catch non-function exports."],"tags":["deno-serve","entrypoint","exports","typescript"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}