Fix MulterError: Unexpected field in Express
This error occurs when the form field name in the multipart request does not match the field name configured in multer. The middleware expects a specific field name but receives a different one. Fix it by ensuring the client form field name matches the multer configuration exactly.
Reading the Stack Trace
Here's what each line means:
- at wrappedFileFilter (/app/node_modules/multer/lib/make-middleware.js:45:19): Multer's file filter rejected the upload because the field name in the request does not match any configured field name.
- at Busboy.<anonymous> (/app/node_modules/multer/lib/make-middleware.js:114:7): Busboy, the underlying multipart parser, detected a file field and passed it to multer's filter which rejected it.
- at HeaderParser._finish (/app/node_modules/busboy/lib/utils.js:312:10): The multipart header parser finished reading the part headers and is now dispatching the field to multer.
Common Causes
1. Mismatched field name between client and server
The HTML form or fetch call uses a different field name than what multer.single() or multer.fields() expects.
// Server expects 'avatar'
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('avatar'), (req, res) => {
res.json({ file: req.file });
});
// Client sends 'profileImage'
// <input type="file" name="profileImage" />
2. Using upload.single() for multiple files
The client sends multiple files but multer is configured with .single(), which only accepts one file field.
const upload = multer({ dest: 'uploads/' });
// Only accepts one file, but form sends multiple
app.post('/upload', upload.single('photo'), (req, res) => {
res.json({ file: req.file });
});
3. No error handling for multer errors
The application does not catch MulterError, so the error propagates as an unhandled 500 instead of a descriptive 400.
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('avatar'), (req, res) => {
res.json({ file: req.file });
});
// No multer error handler
The Fix
Wrap the multer middleware call manually so you can catch MulterError and return a helpful 400 response that tells the client which field name to use. Also add a file size limit to prevent oversized uploads.
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('avatar'), (req, res) => {
res.json({ file: req.file });
});
const multer = require('multer');
const upload = multer({
dest: 'uploads/',
limits: { fileSize: 5 * 1024 * 1024 } // 5MB limit
});
app.post('/upload', (req, res) => {
upload.single('avatar')(req, res, (err) => {
if (err instanceof multer.MulterError) {
return res.status(400).json({ error: `Upload error: ${err.message}`, field: err.field });
}
if (err) {
return res.status(500).json({ error: 'Upload failed' });
}
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded. Use field name: avatar' });
}
res.json({ file: req.file });
});
});
Testing the Fix
const request = require('supertest');
const express = require('express');
const multer = require('multer');
const path = require('path');
function createApp() {
const app = express();
const upload = multer({ dest: '/tmp/test-uploads/' });
app.post('/upload', (req, res) => {
upload.single('avatar')(req, res, (err) => {
if (err instanceof multer.MulterError) {
return res.status(400).json({ error: `Upload error: ${err.message}` });
}
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded. Use field name: avatar' });
}
res.json({ filename: req.file.originalname });
});
});
return app;
}
describe('POST /upload', () => {
it('returns 400 for wrong field name', async () => {
const res = await request(createApp())
.post('/upload')
.attach('wrongField', Buffer.from('test'), 'test.txt');
expect(res.status).toBe(400);
expect(res.body.error).toContain('Upload error');
});
it('uploads successfully with correct field name', async () => {
const res = await request(createApp())
.post('/upload')
.attach('avatar', Buffer.from('test'), 'test.txt');
expect(res.status).toBe(200);
expect(res.body.filename).toBe('test.txt');
});
});
Run your tests:
npx jest --testPathPattern=multer
Pushing Through CI/CD
git checkout -b fix/express-multer-upload-error,git add src/routes/upload.js src/__tests__/multer.test.js,git commit -m "fix: handle MulterError with descriptive 400 response",git push origin fix/express-multer-upload-error
Your CI config should look something like this:
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npx jest --coverage
- run: npm run lint
The Full Manual Process: 18 Steps
Here's every step you just went through to fix this one bug:
- Notice the error alert or see it in your monitoring tool
- Open the error dashboard and read the stack trace
- Identify the file and line number from the stack trace
- Open your IDE and navigate to the file
- Read the surrounding code to understand context
- Reproduce the error locally
- Identify the root cause
- Write the fix
- Run the test suite locally
- Fix any failing tests
- Write new tests covering the edge case
- Run the full test suite again
- Create a new git branch
- Commit and push your changes
- Open a pull request
- Wait for code review
- Merge and deploy to production
- Monitor production to confirm the error is resolved
Total time: 30-60 minutes. For one bug.
Or Let bugstack Fix It in Under 2 minutes
Every step above? bugstack does it automatically.
Step 1: Install the SDK
npm install bugstack-sdk
Step 2: Initialize
const { initBugStack } = require('bugstack-sdk')
initBugStack({ apiKey: process.env.BUGSTACK_API_KEY })
Step 3: There is no step 3.
bugstack handles everything from here:
- Captures the stack trace and request context
- Pulls the relevant source files from your GitHub repo
- Analyzes the error and understands the code context
- Generates a minimal, verified fix
- Runs your existing test suite
- Pushes through your CI/CD pipeline
- Deploys to production (or opens a PR for review)
Time from error to fix deployed: Under 2 minutes.
Human involvement: zero.
Try bugstack Free →No credit card. 5-minute setup. Cancel anytime.
Deploying the Fix (Manual Path)
- Run the test suite locally to confirm multer errors return descriptive 400 responses.
- Open a pull request with the upload error handling changes.
- Wait for CI checks to pass on the PR.
- Have a teammate review and approve the PR.
- Merge to main and test file uploads in staging before promoting to production.
Frequently Asked Questions
BugStack tests uploads with correct and incorrect field names, oversized files, and missing files, then verifies proper error responses before marking it safe to deploy.
Every fix is delivered as a pull request with full CI validation. Your team reviews and approves before anything reaches production.
Yes. Use upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 5 }]) to accept multiple named fields with individual limits.
For production, use cloud storage (S3, GCS) via multer-s3 or similar. Memory storage works for small files you process immediately, and disk storage works for local development.