{"record":{"id":"163be7acd23f57f7","repo":"pinojs/pino","slug":"exported-worker-is-not-a-function","errorCode":null,"errorMessage":"exported worker is not a function","messagePattern":"exported worker is not a function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/transport-stream.js","lineNumber":53,"sourceCode":"      // When bundled with pkg, an undefined error is thrown when called with realImport\n      // When bundled with pkg and using node v20, an ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING error is thrown when called with realImport\n      // More info at: https://github.com/pinojs/thread-stream/issues/143\n      try {\n        fn = realRequire(decodeURIComponent(target))\n      } catch {\n        throw error\n      }\n    } else {\n      throw error\n    }\n  }\n\n  // Depending on how the default export is performed, and on how the code is\n  // transpiled, we may find cases of two nested \"default\" objects.\n  // See https://github.com/pinojs/pino/issues/1243#issuecomment-982774762\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn !== 'function') throw Error('exported worker is not a function')\n\n  return fn\n}\n","sourceCodeStart":35,"sourceCodeEnd":57,"githubUrl":"https://github.com/pinojs/pino/blob/5aa62305c57709ebd6f6b7c328e8830eeb29b297/lib/transport-stream.js#L35-L57","documentation":"When a transport is loaded, Pino imports the transport module and unwraps its exported builder function, tolerating up to two nested .default exports from transpilation (ESM/TS interop). If after unwrapping the export is still not a function, the transport module's export shape is invalid.","triggerScenarios":"Passing transport.target pointing at a module whose export is an object, class instance, or arrow-assigned object without a callable default; e.g. module.exports = { myTransport } without .default, or a CommonJS module exporting a non-function.","commonSituations":"Custom TypeScript transports compiled with esModuleInterop producing nested default objects deeper than Pino's double-unwrap; writing a transport as a plain object instead of a function; wrong file path resolving to a barrel file exporting an object; forgetting module.exports = fn in CJS.","solutions":["Export a function from the transport module: module.exports = async function (opts) { ... } or export default async function (opts) { ... }.","If the export is an object, add a callable default export.","Check the resolved path in transport.target points at the transport file, not an index that re-exports an object.","If transpiled output has >2 nested defaults, restructure the export so the function is at default or module.exports directly.","Test with node -e \"const m=require('./my-transport.js'); console.log(typeof (m.default||m))\" to verify it resolves to 'function'."],"exampleFix":"// before (my-transport.js)\nexport default { build: async (opts) => buildStream }\n// after\nexport default async function (opts) {\n  return buildStream\n}","handlingStrategy":"validation","validationCode":"function validateTransportModule(target) {\n  const mod = require(require.resolve(target))\n  let fn = mod\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn !== 'function') {\n    throw new TypeError(`Transport ${target} must export a function, got ${typeof fn}`)\n  }\n  return true\n}","typeGuard":"const isTransportFn = (mod) => {\n  let fn = mod\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn === 'object') fn = fn.default\n  return typeof fn === 'function'\n}","tryCatchPattern":"try {\n  const logger = pino({ transport: { target } })\n} catch (err) {\n  if (err.message === 'exported worker is not a function') {\n    console.error(`Fix export in ${target}: default-export or module.exports a function`)\n  }\n  throw err\n}","preventionTips":["Always export the transport builder as a default export (ESM/TS) or as module.exports (CJS)","Smoke-test the module standalone: require it and assert typeof is 'function'","Verify transport.target resolves to the actual transport file, not a re-exporting barrel","Add a unit test that builds the transport before relying on it in production"],"tags":["pino","transport","worker","module-exports"],"backgroundTag":"invalid-transport-export","analyzedSha":"5aa62305c57709ebd6f6b7c328e8830eeb29b297","analyzedAt":"2026-09-02T22:05:21.418Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}