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

  1. 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.
  2. 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.
  3. 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.
  4. 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

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.