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
- Ensure `streamHandler` is only set in options when you have an actual function, e.g. `multer({ streamHandler: myHandler })` where `typeof myHandler === 'function'`
- 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
- 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)
- 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
- Never pass a bare string/boolean for streamHandler — always pass the function reference itself
- Destructure function exports from handler modules instead of passing the module object
- Validate the whole options object with a schema (e.g. a tiny check function or zod with a custom function validator) before constructing Multer
- Only include the streamHandler key in the options object when a handler is actually configured (delete the key otherwise)
- Pin and read the Multer version's option docs when upgrading, since option types can change between versions
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)