0
# Error Handling
1
2
Comprehensive error handling system for upload failures, validation errors, and limit violations with custom error types and detailed error reporting.
3
4
## Capabilities
5
6
### MulterError Class
7
8
Custom error class for Multer-specific errors with standardized error codes and optional field information.
9
10
```javascript { .api }
11
/**
12
* Custom error class for Multer-specific upload errors
13
* @param code - Error code indicating the type of error
14
* @param field - Optional field name where the error occurred
15
*/
16
class MulterError extends Error {
17
constructor(code: string, field?: string);
18
/** Error code indicating the specific type of error */
19
code: string;
20
/** Field name where the error occurred (if applicable) */
21
field?: string;
22
/** Human-readable error message */
23
message: string;
24
/** Error class name */
25
name: string;
26
}
27
```
28
29
### Error Codes
30
31
Standard error codes for different types of upload failures:
32
33
```javascript { .api }
34
/** Too many parts in the multipart form */
35
const LIMIT_PART_COUNT = 'LIMIT_PART_COUNT';
36
37
/** File size exceeds the specified limit */
38
const LIMIT_FILE_SIZE = 'LIMIT_FILE_SIZE';
39
40
/** Too many files uploaded */
41
const LIMIT_FILE_COUNT = 'LIMIT_FILE_COUNT';
42
43
/** Field name is too long */
44
const LIMIT_FIELD_KEY = 'LIMIT_FIELD_KEY';
45
46
/** Field value is too long */
47
const LIMIT_FIELD_VALUE = 'LIMIT_FIELD_VALUE';
48
49
/** Too many fields in the form */
50
const LIMIT_FIELD_COUNT = 'LIMIT_FIELD_COUNT';
51
52
/** File uploaded to unexpected field */
53
const LIMIT_UNEXPECTED_FILE = 'LIMIT_UNEXPECTED_FILE';
54
55
/** Field name is missing */
56
const MISSING_FIELD_NAME = 'MISSING_FIELD_NAME';
57
```
58
59
### Error Handling Patterns
60
61
```javascript { .api }
62
/**
63
* Express error handler specifically for multer errors
64
* @param err - Error object (potentially MulterError)
65
* @param req - Express request object
66
* @param res - Express response object
67
* @param next - Express next function
68
*/
69
type MulterErrorHandler = (
70
err: Error | MulterError,
71
req: Request,
72
res: Response,
73
next: NextFunction
74
) => void;
75
```
76
77
**Usage Examples:**
78
79
```javascript
80
const multer = require('multer');
81
const upload = multer({
82
dest: 'uploads/',
83
limits: {
84
fileSize: 1024 * 1024 * 2, // 2MB limit
85
files: 3 // Maximum 3 files
86
}
87
});
88
89
// Method 1: Handle errors in middleware callback
90
app.post('/upload', (req, res) => {
91
upload.single('file')(req, res, (err) => {
92
if (err instanceof multer.MulterError) {
93
// Multer-specific error occurred
94
switch (err.code) {
95
case 'LIMIT_FILE_SIZE':
96
return res.status(400).json({
97
error: 'File too large',
98
message: `File size exceeds 2MB limit`,
99
field: err.field
100
});
101
case 'LIMIT_FILE_COUNT':
102
return res.status(400).json({
103
error: 'Too many files',
104
message: 'Maximum 3 files allowed'
105
});
106
case 'LIMIT_UNEXPECTED_FILE':
107
return res.status(400).json({
108
error: 'Unexpected file',
109
message: `Unexpected file in field: ${err.field}`
110
});
111
default:
112
return res.status(400).json({
113
error: 'Upload error',
114
message: err.message,
115
code: err.code
116
});
117
}
118
} else if (err) {
119
// Other error (e.g., from fileFilter)
120
return res.status(400).json({
121
error: 'Upload failed',
122
message: err.message
123
});
124
}
125
126
// No error - upload successful
127
res.json({
128
success: true,
129
file: req.file
130
});
131
});
132
});
133
134
// Method 2: Use Express error handler middleware
135
app.post('/upload-with-middleware', upload.single('file'), (req, res) => {
136
res.json({
137
success: true,
138
file: req.file
139
});
140
});
141
142
// Global error handler for multer errors
143
app.use((err, req, res, next) => {
144
if (err instanceof multer.MulterError) {
145
const errorResponses = {
146
'LIMIT_FILE_SIZE': {
147
status: 413,
148
message: 'File too large'
149
},
150
'LIMIT_FILE_COUNT': {
151
status: 400,
152
message: 'Too many files'
153
},
154
'LIMIT_FIELD_COUNT': {
155
status: 400,
156
message: 'Too many fields'
157
},
158
'LIMIT_FIELD_KEY': {
159
status: 400,
160
message: 'Field name too long'
161
},
162
'LIMIT_FIELD_VALUE': {
163
status: 400,
164
message: 'Field value too long'
165
},
166
'LIMIT_PART_COUNT': {
167
status: 400,
168
message: 'Too many parts'
169
},
170
'LIMIT_UNEXPECTED_FILE': {
171
status: 400,
172
message: `Unexpected file in field: ${err.field}`
173
},
174
'MISSING_FIELD_NAME': {
175
status: 400,
176
message: 'Field name missing'
177
}
178
};
179
180
const errorResponse = errorResponses[err.code] || {
181
status: 400,
182
message: 'Upload error'
183
};
184
185
return res.status(errorResponse.status).json({
186
error: err.code,
187
message: errorResponse.message,
188
field: err.field
189
});
190
}
191
192
// Handle other errors
193
next(err);
194
});
195
```
196
197
### File Filter Errors
198
199
File filter functions can throw errors to reject files:
200
201
```javascript
202
const imageFilter = (req, file, cb) => {
203
if (file.mimetype.startsWith('image/')) {
204
cb(null, true);
205
} else {
206
// Throw error to reject file
207
cb(new Error('Only image files are allowed'), false);
208
}
209
};
210
211
const upload = multer({
212
dest: 'uploads/',
213
fileFilter: imageFilter
214
});
215
216
app.post('/upload-image', upload.single('image'), (req, res) => {
217
// This will be handled by error middleware if file filter rejects
218
res.json({ success: true, file: req.file });
219
});
220
```
221
222
### Storage Engine Errors
223
224
Storage engines can also generate errors during file handling:
225
226
```javascript
227
const problematicStorage = multer.diskStorage({
228
destination: (req, file, cb) => {
229
// Check if directory is writable
230
const dest = './uploads';
231
fs.access(dest, fs.constants.W_OK, (err) => {
232
if (err) {
233
cb(new Error('Upload directory not writable'), null);
234
} else {
235
cb(null, dest);
236
}
237
});
238
},
239
filename: (req, file, cb) => {
240
// Check for duplicate filenames
241
const filename = file.originalname;
242
const fullPath = path.join('./uploads', filename);
243
244
fs.access(fullPath, fs.constants.F_OK, (err) => {
245
if (!err) {
246
// File exists - generate unique name
247
const timestamp = Date.now();
248
const ext = path.extname(filename);
249
const base = path.basename(filename, ext);
250
cb(null, `${base}-${timestamp}${ext}`);
251
} else {
252
cb(null, filename);
253
}
254
});
255
}
256
});
257
```
258
259
### Advanced Error Handling
260
261
```javascript
262
// Comprehensive error handling with logging
263
const createUploadHandler = (uploadConfig) => {
264
const upload = multer(uploadConfig);
265
266
return (req, res, next) => {
267
upload.single('file')(req, res, (err) => {
268
if (err) {
269
// Log error for debugging
270
console.error('Upload error:', {
271
error: err.message,
272
code: err.code,
273
field: err.field,
274
user: req.user?.id,
275
timestamp: new Date().toISOString(),
276
ip: req.ip,
277
userAgent: req.headers['user-agent']
278
});
279
280
// Send appropriate response
281
if (err instanceof multer.MulterError) {
282
return res.status(400).json({
283
success: false,
284
error: err.code,
285
message: getErrorMessage(err.code),
286
field: err.field
287
});
288
} else {
289
return res.status(500).json({
290
success: false,
291
error: 'UPLOAD_FAILED',
292
message: 'File upload failed'
293
});
294
}
295
}
296
297
next();
298
});
299
};
300
};
301
302
const getErrorMessage = (code) => {
303
const messages = {
304
'LIMIT_FILE_SIZE': 'File size exceeds maximum allowed size',
305
'LIMIT_FILE_COUNT': 'Too many files uploaded',
306
'LIMIT_FIELD_COUNT': 'Too many form fields',
307
'LIMIT_FIELD_KEY': 'Field name is too long',
308
'LIMIT_FIELD_VALUE': 'Field value is too long',
309
'LIMIT_PART_COUNT': 'Too many parts in multipart form',
310
'LIMIT_UNEXPECTED_FILE': 'File uploaded to unexpected field',
311
'MISSING_FIELD_NAME': 'Field name is required'
312
};
313
314
return messages[code] || 'Upload error occurred';
315
};
316
317
// Usage
318
app.post('/secure-upload',
319
createUploadHandler({
320
dest: 'uploads/',
321
limits: {
322
fileSize: 5 * 1024 * 1024, // 5MB
323
files: 1
324
}
325
}),
326
(req, res) => {
327
res.json({
328
success: true,
329
file: req.file
330
});
331
}
332
);
333
```
334
335
### Client-Side Error Handling
336
337
For handling errors on the client side:
338
339
```javascript
340
// Fetch API example
341
const uploadFile = async (file) => {
342
const formData = new FormData();
343
formData.append('file', file);
344
345
try {
346
const response = await fetch('/upload', {
347
method: 'POST',
348
body: formData
349
});
350
351
const result = await response.json();
352
353
if (!response.ok) {
354
// Handle different error types
355
switch (result.error) {
356
case 'LIMIT_FILE_SIZE':
357
throw new Error('File is too large. Maximum size is 2MB.');
358
case 'LIMIT_FILE_COUNT':
359
throw new Error('Too many files. Maximum is 3 files.');
360
case 'LIMIT_UNEXPECTED_FILE':
361
throw new Error(`File uploaded to wrong field: ${result.field}`);
362
default:
363
throw new Error(result.message || 'Upload failed');
364
}
365
}
366
367
return result;
368
} catch (error) {
369
console.error('Upload error:', error.message);
370
throw error;
371
}
372
};
373
374
// Usage in form handler
375
document.getElementById('uploadForm').onsubmit = async (e) => {
376
e.preventDefault();
377
const fileInput = document.getElementById('fileInput');
378
379
if (fileInput.files.length === 0) {
380
alert('Please select a file');
381
return;
382
}
383
384
try {
385
const result = await uploadFile(fileInput.files[0]);
386
alert('Upload successful!');
387
} catch (error) {
388
alert(`Upload failed: ${error.message}`);
389
}
390
};
391
```