{"id":"af74b68b67037989","repo":"expressjs/multer","slug":"unknown-file-strategy","errorCode":null,"errorMessage":"Unknown file strategy: ","messagePattern":"Unknown file strategy: ","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"lib/file-appender.js","lineNumber":15,"sourceCode":"function arrayRemove (arr, item) {\n  var idx = arr.indexOf(item)\n  if (~idx) arr.splice(idx, 1)\n}\n\nfunction FileAppender (strategy, req) {\n  this.strategy = strategy\n  this.req = req\n\n  switch (strategy) {\n    case 'NONE': break\n    case 'VALUE': break\n    case 'ARRAY': req.files = []; break\n    case 'OBJECT': req.files = Object.create(null); break\n    default: throw new Error('Unknown file strategy: ' + strategy)\n  }\n}\n\nFileAppender.prototype.insertPlaceholder = function (file) {\n  var placeholder = {\n    fieldname: file.fieldname\n  }\n\n  switch (this.strategy) {\n    case 'NONE': break\n    case 'VALUE': break\n    case 'ARRAY': this.req.files.push(placeholder); break\n    case 'OBJECT':\n      if (this.req.files[file.fieldname]) {\n        this.req.files[file.fieldname].push(placeholder)\n      } else {\n        this.req.files[file.fieldname] = [placeholder]\n      }","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/expressjs/multer/blob/2e2af08157c66cbbc76539ccbd8869097a0c8feb/lib/file-appender.js#L1-L33","documentation":"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.","triggerScenarios":"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.","commonSituations":"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`.","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."],"exampleFix":"// before — a custom extension forgetting the strategy argument\nconst Multer = require('multer')\nMulter.prototype.mySingle = function (name) {\n  return this._makeMiddleware([{ name, maxCount: 1 }]) // strategy undefined -> 'Unknown file strategy: '\n}\n\n// after — pass the strategy literal explicitly\nconst Multer = require('multer')\nMulter.prototype.mySingle = function (name) {\n  return this._makeMiddleware([{ name, maxCount: 1 }], 'VALUE')\n}","handlingStrategy":"type-guard","validationCode":"const { prototype } = require('multer')\nconst VALID_STRATEGIES = new Set(['NONE', 'VALUE', 'ARRAY', 'OBJECT'])\n\n// Sanity check the installed multer exposes the expected internal contract\nconst FileAppender = require('multer/lib/file-appender')\nconst sample = new FileAppender('VALUE', { files: null })\nif (!sample || sample.strategy !== 'VALUE') {\n  throw new Error('Installed multer has an incompatible file-appender; reinstall or pin the version')\n}\nif (!VALID_STRATEGIES.has(sample.strategy)) {\n  throw new Error('Unknown multer file strategy contract: ' + sample.strategy)\n}","typeGuard":"const VALID_STRATEGIES = new Set(['NONE', 'VALUE', 'ARRAY', 'OBJECT'])\nfunction isFileStrategy(value) {\n  return typeof value === 'string' && VALID_STRATEGIES.has(value)\n}","tryCatchPattern":"// This is an internal invariant — catching it is a last resort. Prefer preventing\n// duplicate installations (see preventionTips). If you must wrap an extension:\ntry {\n  middleware = multer({ storage }).single('file') // strategy set internally to 'VALUE'\n} catch (err) {\n  if (/Unknown file strategy/.test(err.message)) {\n    // surface a clearer message pointing at a likely duplicated/patched install\n    throw new Error('multer internal contract broken — run `npm ls multer` and dedupe, then reinstall')\n  }\n  throw err\n}","preventionTips":["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."],"tags":["internal-invariant","bundling","version-mismatch","monkeypatch","configuration"],"analyzedSha":"2e2af08157c66cbbc76539ccbd8869097a0c8feb","analyzedAt":"2026-08-03T19:14:03.302Z","schemaVersion":2}