or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-middleware.mderror-handling.mdindex.mdstorage-engines.md

error-handling.mddocs/

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

```