{"record":{"id":"b8bcb19ba12c4a17","repo":"pinojs/pino","slug":"pino-transmit-option-must-have-a-send-function","errorCode":null,"errorMessage":"pino: transmit option must have a send function","messagePattern":"pino: transmit option must have a send function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browser.js","lineNumber":95,"sourceCode":"function shouldSerialize (serialize, serializers) {\n  if (Array.isArray(serialize)) {\n    const hasToFilter = serialize.filter(function (k) {\n      return k !== '!stdSerializers.err'\n    })\n    return hasToFilter\n  } else if (serialize === true) {\n    return Object.keys(serializers)\n  }\n\n  return false\n}\n\nfunction pino (opts) {\n  opts = opts || {}\n  opts.browser = opts.browser || {}\n\n  const transmit = opts.browser.transmit\n  if (transmit && typeof transmit.send !== 'function') { throw Error('pino: transmit option must have a send function') }\n\n  const proto = opts.browser.write || _console\n  if (opts.browser.write) opts.browser.asObject = true\n  const serializers = opts.serializers || {}\n  const serialize = shouldSerialize(opts.browser.serialize, serializers)\n  let stdErrSerialize = opts.browser.serialize\n\n  if (\n    Array.isArray(opts.browser.serialize) &&\n    opts.browser.serialize.indexOf('!stdSerializers.err') > -1\n  ) stdErrSerialize = false\n\n  const customLevels = Object.keys(opts.customLevels || {})\n  const levels = ['error', 'fatal', 'warn', 'info', 'debug', 'trace'].concat(customLevels)\n\n  if (typeof proto === 'function') {\n    levels.forEach(function (level) {\n      proto[level] = proto","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/pinojs/pino/blob/5aa62305c57709ebd6f6b7c328e8830eeb29b297/browser.js#L77-L113","documentation":"In the browser build, pino() checks that opts.browser.transmit.send is a function when transmit is provided. The transmit option powers client-side log shipping; without a send function the library cannot transmit anything, so it throws immediately.","triggerScenarios":"pino({ browser: { transmit: { } } }) or transmit: { send: 'url' } — transmit object present but send missing or not a function.","commonSituations":"Copy-pasting transmit config examples and forgetting the send callback; setting send to a URL string expecting the library to do the HTTP request itself; conditional config that leaves an empty transmit object.","solutions":["Provide a send function: transmit: { level: 'error', send: (level, logEvent) => { ... } }","Remove the transmit option entirely if you don't need log shipping","Guard the config so transmit is only set when a send function exists"],"exampleFix":"// before\npino({ browser: { transmit: { level: 'error' } } });\n// after\npino({ browser: { transmit: { level: 'error', send: (level, logEvent) => fetch('/logs', { method: 'POST', body: JSON.stringify(logEvent) }) } } });","handlingStrategy":"type-guard","validationCode":"function assertTransmit(browser = {}) {\n  if (browser.transmit && typeof browser.transmit.send !== 'function') {\n    throw new Error('browser.transmit.send must be a function');\n  }\n}","typeGuard":"function hasSendFn(browser) {\n  return !browser.transmit || typeof browser.transmit.send === 'function';\n}","tryCatchPattern":"try { logger = pino(opts); } catch (e) { if (/transmit option must have a send function/.test(e.message)) { delete opts.browser.transmit; logger = pino(opts); } else { throw e; } }","preventionTips":["Always define send together with transmit: { transmit: { level, send } }","Note that pino does not perform HTTP itself — send must implement the shipping (e.g. fetch/XHR)","Type the browser options so transmit.send is required when transmit exists"],"tags":["logging","pino","browser","transmit","validation"],"backgroundTag":"missing-callback-function","analyzedSha":"5aa62305c57709ebd6f6b7c328e8830eeb29b297","analyzedAt":"2026-09-02T22:05:21.418Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}