expressjs/multer · error · TypeError

Expected streamHandler to be a function

Error message

Expected streamHandler to be a function

What it means

Multer (as constructed here) accepts an optional `streamHandler` option that must be a function if provided. During configuration parsing (index.js:102) it explicitly checks `options.streamHandler !== undefined && typeof options.streamHandler !== 'function'` and throws a TypeError immediately, so a misconfigured options object fails fast rather than failing later when the handler is invoked. This is an input-validation guard on the constructor options surface.

Solutions

  1. Ensure `streamHandler` is only set in options when you have an actual function, e.g. `multer({ streamHandler: myHandler })` where `typeof myHandler === 'function'`
  2. Remove the `streamHandler` key entirely (or set it to undefined) if you do not intend to customize stream handling — the library defaults it to undefined
  3. If the handler comes from config or an import, check `typeof handler === 'function'` before constructing Multer, and fix the import (use the module's function export, not the module object)
  4. If the value comes from JSON config, resolve it to a function in code (e.g. a lookup map from name to function) instead of passing the raw string

Example fix

// before
const handler = require('./stream-handler'); // module object, not a function
const upload = multer({ streamHandler: handler });
// throws: Expected streamHandler to be a function

// after
const { streamHandler } = require('./stream-handler'); // destructure the function
const upload = multer({ streamHandler: streamHandler });
// or simply omit it:
// const upload = multer({});
Defensive patterns

Strategy: validation

Validate before calling

function buildMulterOptions(options = {}) {
  if (options.streamHandler !== undefined && typeof options.streamHandler !== 'function') {
    throw new TypeError(
      `streamHandler must be a function or undefined, got ${typeof options.streamHandler}`
    );
  }
  return options;
}
const upload = multer(buildMulterOptions(myOptions));

Type guard

function isStreamHandlerOptions(options) {
  return (
    options.streamHandler === undefined ||
    typeof options.streamHandler === 'function'
  );
}

if (!isStreamHandlerOptions(myOptions)) {
  throw new TypeError('streamHandler must be a function if provided');
}

Try / catch

try {
  upload = multer(options);
} catch (err) {
  if (err instanceof TypeError && /streamHandler/.test(err.message)) {
    console.error('Bad streamHandler option; expected a function, got:', typeof options.streamHandler);
    upload = multer({ ...options, streamHandler: undefined });
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Passing `streamHandler` in the Multer options object with a non-function value: e.g. `multer({ streamHandler: true })`, `multer({ streamHandler: 'myHandler' })`, `multer({ streamHandler: null })` (null !== undefined so it is checked), or referencing an undefined-yet-typed/wrong import such as `streamHandler: myModule.handler` where handler is an object or undefined-then-assigned wrong type. Only a value of exactly `undefined` (or omitting the key) is accepted as 'not provided'.

Common situations: Copy-pasting configuration from docs where the option was renamed; passing a handler name string instead of the function reference; requiring a handler module and forgetting the property is a default export wrapper; typos where `streamHandler` collides with another string-typed option; JSON-loaded config objects where functions cannot be represented so values arrive as strings; upgrading Multer versions where streamHandler was newly added and old code passed a string/boolean flag.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.


AI-assisted analysis of expressjs/multer@35979e5afb (2026-09-20). Data as JSON: /api/errors/bbce81d85463f61b. Report an issue: GitHub.

Appendix: source

Thrown at index.js:102

    this.storage = options.storage
  } else if (options.dest) {
    this.storage = diskStorage({ destination: options.dest })
  } else {
    this.storage = memoryStorage()
  }

  if (options.limits && typeof options.limits !== 'function') validateLimits(options.limits)

  this.limits = options.limits
  this.preservePath = options.preservePath
  this.defParamCharset = options.defParamCharset || 'latin1'
  this.defCharset = options.defCharset
  this.highWaterMark = options.highWaterMark
  this.fileHwm = options.fileHwm
  this.fileFilter = options.fileFilter || allowAll

  if (options.streamHandler !== undefined && typeof options.streamHandler !== 'function') {
    throw new TypeError('Expected streamHandler to be a function')
  }

  this.streamHandler = options.streamHandler
}

Multer.prototype._makeMiddleware = function (fields, fileStrategy) {
  function setup () {
    var fileFilter = this.fileFilter
    var filesLeft = Object.create(null)

    fields.forEach(function (field) {
      if (typeof field.maxCount === 'number') {
        filesLeft[field.name] = field.maxCount
      } else {
        filesLeft[field.name] = Infinity
      }
    })

View on GitHub (pinned to 35979e5afb)