expressjs/multer · critical · Error
Unknown file strategy:
Error message
Unknown file strategy:
What it means
Thrown by the FileAppender constructor in lib/file-appender.js:15 when the `strategy` argument does not match one of the four known values: 'NONE', 'VALUE', 'ARRAY', or 'OBJECT'. The FileAppender uses the strategy to decide how to shape `req.files` (array vs. keyed object vs. single `req.file`), and an unrecognized value would silently produce inconsistent request state, so the constructor asserts. This strategy is set internally by Multer.prototype._makeMiddleware in index.js:54 from a hardcoded literal passed by `.single()`/`.array()`/`.fields()`/`.none()` — it is never sourced from user input, so reaching this branch implies internal corruption, monkeypatching, or a version mismatch rather than a normal API mistake.
Source
Thrown at lib/file-appender.js:15
function arrayRemove (arr, item) {
var idx = arr.indexOf(item)
if (~idx) arr.splice(idx, 1)
}
function FileAppender (strategy, req) {
this.strategy = strategy
this.req = req
switch (strategy) {
case 'NONE': break
case 'VALUE': break
case 'ARRAY': req.files = []; break
case 'OBJECT': req.files = Object.create(null); break
default: throw new Error('Unknown file strategy: ' + strategy)
}
}
FileAppender.prototype.insertPlaceholder = function (file) {
var placeholder = {
fieldname: file.fieldname
}
switch (this.strategy) {
case 'NONE': break
case 'VALUE': break
case 'ARRAY': this.req.files.push(placeholder); break
case 'OBJECT':
if (this.req.files[file.fieldname]) {
this.req.files[file.fieldname].push(placeholder)
} else {
this.req.files[file.fieldname] = [placeholder]
}View on GitHub (pinned to 2e2af08157)
Solutions
- Clear all caches and reinstall: remove node_modules and lockfile-derived transients (rm -rf node_modules && npm install / yarn install) to eliminate a half-upgraded install.
- If using a bundler, ensure multer is not duplicated — run `npm ls multer` and dedupe so only one version resolves, and configure resolve.alias/aliasFields so the internal `./lib/...` requires resolve to the same physical files as the main entry.
- Remove any monkeypatches or custom subclasses overriding `Multer.prototype._makeMiddleware` or `Multer.prototype.single/array/fields/none` — pass the strategy literal ('VALUE' | 'ARRAY' | 'OBJECT' | 'NONE') explicitly when extending.
- Pin multer to a single exact version in package.json and verify with `npm ls multer` that no transitive dependency pulls a different major.
Example fix
// before — a custom extension forgetting the strategy argument
const Multer = require('multer')
Multer.prototype.mySingle = function (name) {
return this._makeMiddleware([{ name, maxCount: 1 }]) // strategy undefined -> 'Unknown file strategy: '
}
// after — pass the strategy literal explicitly
const Multer = require('multer')
Multer.prototype.mySingle = function (name) {
return this._makeMiddleware([{ name, maxCount: 1 }], 'VALUE')
} Defensive patterns
Strategy: type-guard
Validate before calling
const { prototype } = require('multer')
const VALID_STRATEGIES = new Set(['NONE', 'VALUE', 'ARRAY', 'OBJECT'])
// Sanity check the installed multer exposes the expected internal contract
const FileAppender = require('multer/lib/file-appender')
const sample = new FileAppender('VALUE', { files: null })
if (!sample || sample.strategy !== 'VALUE') {
throw new Error('Installed multer has an incompatible file-appender; reinstall or pin the version')
}
if (!VALID_STRATEGIES.has(sample.strategy)) {
throw new Error('Unknown multer file strategy contract: ' + sample.strategy)
} Type guard
const VALID_STRATEGIES = new Set(['NONE', 'VALUE', 'ARRAY', 'OBJECT'])
function isFileStrategy(value) {
return typeof value === 'string' && VALID_STRATEGIES.has(value)
} Try / catch
// This is an internal invariant — catching it is a last resort. Prefer preventing
// duplicate installations (see preventionTips). If you must wrap an extension:
try {
middleware = multer({ storage }).single('file') // strategy set internally to 'VALUE'
} catch (err) {
if (/Unknown file strategy/.test(err.message)) {
// surface a clearer message pointing at a likely duplicated/patched install
throw new Error('multer internal contract broken — run `npm ls multer` and dedupe, then reinstall')
}
throw err
} Prevention
- Run `npm ls multer` (or `yarn why multer`) in CI and fail the build if more than one version resolves.
- Configure your bundler to treat multer as external (Node module) rather than bundling its internal `./lib/*` requires, which can split the strategy contract.
- Never override Multer.prototype methods without re-passing the strategy literal to `_makeMiddleware`.
- After a major-version upgrade, clear node_modules and any bundler cache (webpack cache, .parcel-cache, tsbuildinfo) before redeploying.
- If forking multer, keep the strategy literals centralized in a single constants module so every internal call site shares one source of truth.
When it happens
Trigger: Calling `new FileAppender(undefined, req)` or `new FileAppender('', req)` directly (the error message literally shows `Unknown file strategy: ` with an empty value, indicating strategy was undefined or coerced to empty string). Indirectly, it surfaces when the internal `fileStrategy` field flowing through make-middleware is missing — e.g. a bundled/transpiled build dropped the property, a monkeypatch overrode `_makeMiddleware` without passing the second argument, or two different multer versions are loaded into the same module graph and their internal symbols disagree.
Common situations: Deduplication failure in a bundler (webpack/rollup/esbuild) producing two `multer` instances with incompatible internal state; a patched/forked multer where a custom upload method forgets to pass the strategy literal to `_makeMiddleware`; upgrading multer across a major version where the internal strategy contract changed while stale code from a cache or a vendored copy is still loaded; or yarn/npm hoisting issues leaving an older `lib/file-appender.js` alongside a newer `index.js`.
Related errors
AI-assisted analysis of expressjs/multer@2e2af08157 (2026-08-03).
Data as JSON: /data/errors/af74b68b67037989.json.
Report an issue: GitHub.