or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aws-lambda.mdbrowser-monitoring.mdcustom-attributes.mdcustom-instrumentation.mddistributed-tracing.mderror-handling.mdindex.mdllm-monitoring.mdmetrics-events.mdsegments-timing.mdtransaction-management.mdurl-naming-rules.mdutilities.md

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive error tracking with custom attributes, error grouping, and expected error marking.

3

4

## Capabilities

5

6

### Notice Error

7

8

Record errors that have been handled by your application code.

9

10

```javascript { .api }

11

/**

12

* Send errors to New Relic that you've already handled. Does not obey

13

* ignore_status_codes configuration.

14

* @param {Error|string} error - The error to be traced

15

* @param {object} [customAttributes] - Optional custom attributes for the error

16

* @param {boolean} [expected] - Whether the error is expected (defaults to false)

17

* @returns {false|undefined} Returns false when disabled/errored, undefined on success

18

*/

19

function noticeError(error, customAttributes, expected);

20

```

21

22

**Usage Examples:**

23

24

```javascript

25

const newrelic = require('newrelic');

26

27

// Basic error reporting

28

try {

29

performSomeTask();

30

} catch (err) {

31

newrelic.noticeError(err);

32

// Handle the error in your application

33

res.status(500).json({ error: 'Internal server error' });

34

}

35

36

// Error with custom attributes

37

try {

38

processPayment(paymentData);

39

} catch (err) {

40

newrelic.noticeError(err, {

41

userId: user.id,

42

paymentMethod: paymentData.method,

43

amount: paymentData.amount,

44

orderContext: 'checkout'

45

});

46

throw err; // Re-throw if needed

47

}

48

49

// Expected errors (tracked but don't affect error rate)

50

try {

51

validateUserInput(input);

52

} catch (validationError) {

53

newrelic.noticeError(validationError, {

54

inputType: 'userRegistration',

55

validationRule: validationError.rule

56

}, true); // Mark as expected

57

58

return res.status(400).json({

59

error: 'Validation failed',

60

details: validationError.message

61

});

62

}

63

64

// String errors (automatically converted to Error objects)

65

if (user.permissions < requiredLevel) {

66

newrelic.noticeError('Insufficient permissions', {

67

userId: user.id,

68

requiredLevel: requiredLevel,

69

userLevel: user.permissions

70

});

71

}

72

```

73

74

### Set Error Group Callback

75

76

Define custom logic for grouping similar errors together in New Relic's Errors Inbox.

77

78

```javascript { .api }

79

/**

80

* Set a custom callback function to generate error group names for the Errors Inbox.

81

* The callback receives error metadata and must return a string.

82

* @param {Function} callback - Synchronous function to generate error.group.name attribute

83

*/

84

function setErrorGroupCallback(callback);

85

```

86

87

**Usage Examples:**

88

89

```javascript

90

// Basic error grouping by error type and HTTP status

91

newrelic.setErrorGroupCallback((metadata) => {

92

const errorType = metadata.error?.name || 'UnknownError';

93

const statusCode = metadata['http.statusCode'];

94

95

if (statusCode) {

96

return `${errorType}-${statusCode}`;

97

}

98

99

return errorType;

100

});

101

102

// Advanced error grouping with business context

103

newrelic.setErrorGroupCallback((metadata) => {

104

const error = metadata.error;

105

const customAttrs = metadata.customAttributes || {};

106

107

// Group validation errors by the field that failed

108

if (error?.name === 'ValidationError' && customAttrs.field) {

109

return `ValidationError-${customAttrs.field}`;

110

}

111

112

// Group payment errors by payment method

113

if (error?.message?.includes('payment') && customAttrs.paymentMethod) {

114

return `PaymentError-${customAttrs.paymentMethod}`;

115

}

116

117

// Group API errors by endpoint

118

if (metadata['request.uri'] && error?.name === 'APIError') {

119

const endpoint = metadata['request.uri'].split('?')[0]; // Remove query params

120

return `APIError-${endpoint}`;

121

}

122

123

// Default grouping

124

return error?.name || 'UnknownError';

125

});

126

127

// Error grouping with user context

128

newrelic.setErrorGroupCallback((metadata) => {

129

const error = metadata.error;

130

const isExpected = metadata['error.expected'];

131

const userTier = metadata.customAttributes?.userTier;

132

133

// Don't group expected errors with unexpected ones

134

const prefix = isExpected ? 'Expected' : 'Unexpected';

135

136

// Group by user tier for business insights

137

if (userTier) {

138

return `${prefix}-${error?.name}-${userTier}`;

139

}

140

141

return `${prefix}-${error?.name || 'UnknownError'}`;

142

});

143

```

144

145

## Error Metadata Structure

146

147

The error group callback receives a metadata object with the following structure:

148

149

```javascript { .api }

150

interface ErrorMetadata {

151

/** Custom attributes passed to noticeError() */

152

customAttributes?: object;

153

/** HTTP request URI */

154

'request.uri'?: string;

155

/** HTTP status code */

156

'http.statusCode'?: string;

157

/** HTTP method */

158

'http.method'?: string;

159

/** The actual Error object */

160

error?: Error;

161

/** Whether the error was marked as expected */

162

'error.expected'?: boolean;

163

}

164

```

165

166

## Configuration and Security

167

168

### High Security Mode

169

170

When high security mode is enabled:

171

- Custom attributes in `noticeError()` are ignored and logged as debug message

172

- The error itself is still recorded

173

174

### Configuration Controls

175

176

- `api.notice_error_enabled: false` - Disables error recording

177

- `api.custom_attributes_enabled: false` - Disables custom attributes on errors

178

179

## Common Usage Patterns

180

181

### API Error Handling with Context

182

183

```javascript

184

app.use('/api', (req, res, next) => {

185

try {

186

next();

187

} catch (error) {

188

const errorContext = {

189

endpoint: req.path,

190

method: req.method,

191

userId: req.user?.id,

192

userAgent: req.get('User-Agent'),

193

ipAddress: req.ip,

194

requestId: req.headers['x-request-id']

195

};

196

197

newrelic.noticeError(error, errorContext);

198

199

res.status(500).json({

200

error: 'Internal server error',

201

requestId: errorContext.requestId

202

});

203

}

204

});

205

```

206

207

### Database Error Handling

208

209

```javascript

210

async function performDatabaseOperation(query, params) {

211

try {

212

return await database.execute(query, params);

213

} catch (error) {

214

const errorContext = {

215

queryType: query.type,

216

tableCount: query.tables?.length || 0,

217

paramCount: params.length,

218

connectionPool: database.pool.name

219

};

220

221

// Mark timeout errors as expected if they're common

222

const isExpected = error.code === 'TIMEOUT' && query.type === 'SELECT';

223

224

newrelic.noticeError(error, errorContext, isExpected);

225

throw error;

226

}

227

}

228

```

229

230

### Validation Error Handling

231

232

```javascript

233

function validateUserData(userData, schema) {

234

try {

235

return schema.validate(userData);

236

} catch (validationError) {

237

// These are expected business logic errors

238

newrelic.noticeError(validationError, {

239

validationType: 'userRegistration',

240

failedField: validationError.field,

241

providedValue: validationError.value,

242

validationRule: validationError.rule

243

}, true); // Mark as expected

244

245

throw validationError;

246

}

247

}

248

```

249

250

### External Service Error Handling

251

252

```javascript

253

async function callExternalAPI(endpoint, data) {

254

try {

255

const response = await httpClient.post(endpoint, data);

256

return response.data;

257

} catch (error) {

258

const errorContext = {

259

externalService: 'payment-processor',

260

endpoint: endpoint,

261

httpStatusCode: error.response?.status,

262

retryAttempt: data.retryCount || 0,

263

requestSize: JSON.stringify(data).length

264

};

265

266

// 4xx errors are typically expected (bad requests)

267

const isExpected = error.response?.status >= 400 && error.response?.status < 500;

268

269

newrelic.noticeError(error, errorContext, isExpected);

270

throw error;

271

}

272

}

273

```

274

275

### Business Logic Error Grouping

276

277

```javascript

278

// Set up comprehensive error grouping

279

newrelic.setErrorGroupCallback((metadata) => {

280

const error = metadata.error;

281

const customAttrs = metadata.customAttributes || {};

282

const uri = metadata['request.uri'] || '';

283

const statusCode = metadata['http.statusCode'];

284

285

// Payment processing errors

286

if (customAttrs.paymentMethod || uri.includes('/payment')) {

287

return `Payment-${customAttrs.paymentMethod || 'Unknown'}-${error?.name}`;

288

}

289

290

// User authentication errors

291

if (uri.includes('/auth') || error?.name === 'AuthenticationError') {

292

return `Auth-${error?.name}-${statusCode}`;

293

}

294

295

// Data validation errors grouped by entity type

296

if (error?.name === 'ValidationError' && customAttrs.entityType) {

297

return `Validation-${customAttrs.entityType}-${customAttrs.failedField || 'Unknown'}`;

298

}

299

300

// Third-party service errors

301

if (customAttrs.externalService) {

302

return `External-${customAttrs.externalService}-${error?.name}`;

303

}

304

305

// Database errors grouped by operation type

306

if (error?.name?.includes('Database') && customAttrs.queryType) {

307

return `Database-${customAttrs.queryType}-${error?.name}`;

308

}

309

310

// Default grouping by error name and status code

311

return `${error?.name || 'UnknownError'}${statusCode ? `-${statusCode}` : ''}`;

312

});

313

```

314

315

### Error Rate Monitoring

316

317

```javascript

318

// Monitor error rates and alert on thresholds

319

let errorCount = 0;

320

let totalRequests = 0;

321

322

app.use((req, res, next) => {

323

totalRequests++;

324

325

res.on('finish', () => {

326

if (res.statusCode >= 500) {

327

errorCount++;

328

329

// Calculate error rate every 100 requests

330

if (totalRequests % 100 === 0) {

331

const errorRate = errorCount / totalRequests;

332

333

newrelic.recordMetric('ErrorRate/Server', errorRate);

334

335

if (errorRate > 0.05) { // Alert if > 5% error rate

336

newrelic.recordCustomEvent('HighErrorRate', {

337

errorRate: errorRate,

338

errorCount: errorCount,

339

totalRequests: totalRequests,

340

alertLevel: 'critical'

341

});

342

}

343

}

344

}

345

});

346

347

next();

348

});

349

```

350

351

### Async Error Handling

352

353

```javascript

354

// Proper async error handling with context preservation

355

async function processAsyncTask(taskData) {

356

const taskContext = {

357

taskId: taskData.id,

358

taskType: taskData.type,

359

userId: taskData.userId,

360

priority: taskData.priority

361

};

362

363

try {

364

const result = await performAsyncOperation(taskData);

365

return result;

366

} catch (error) {

367

// Preserve context when handling async errors

368

newrelic.noticeError(error, {

369

...taskContext,

370

errorOccurredAt: 'asyncTaskProcessing',

371

asyncContext: true

372

});

373

374

// Re-throw to maintain error flow

375

throw error;

376

}

377

}

378

379

// Handling unhandled promise rejections

380

process.on('unhandledRejection', (reason, promise) => {

381

newrelic.noticeError(reason instanceof Error ? reason : new Error(String(reason)), {

382

source: 'unhandledRejection',

383

promiseLocation: promise.toString()

384

});

385

});

386

```