or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-processing.mderror-handling.mdformat-conversion.mdindex.mdreference-resolution.mdutility-functions.mdvalidation.md

error-handling.mddocs/

0

# Error Handling

1

2

Custom error classes and utility functions for managing validation errors, compilation, and error reporting with contextual information.

3

4

## Capabilities

5

6

### ValidationError Class

7

8

Custom error class that extends the standard Error class, specifically designed for API validation failures.

9

10

```typescript { .api }

11

/**

12

* Custom error class for validation failures

13

* Extends standard Error with specific name for validation contexts

14

*/

15

class ValidationError extends Error {

16

constructor(message: string);

17

name: 'ValidationError';

18

}

19

```

20

21

**Usage Examples:**

22

23

```typescript

24

import { ValidationError } from "oas-normalize/lib/errors";

25

26

// Catching validation errors

27

const oas = new OASNormalize(invalidSpec);

28

29

try {

30

await oas.validate();

31

} catch (error) {

32

if (error instanceof ValidationError) {

33

console.error('Validation failed:', error.message);

34

console.log('Error type:', error.name); // "ValidationError"

35

console.log('Stack trace:', error.stack);

36

} else {

37

console.error('Unexpected error:', error);

38

}

39

}

40

```

41

42

```typescript

43

// Custom validation error handling

44

function handleAPIValidation(spec: any) {

45

return new OASNormalize(spec)

46

.validate()

47

.catch(error => {

48

if (error instanceof ValidationError) {

49

// Handle validation-specific errors

50

return {

51

success: false,

52

validationError: true,

53

message: error.message,

54

details: parseValidationMessage(error.message)

55

};

56

}

57

58

// Re-throw other errors

59

throw error;

60

});

61

}

62

```

63

64

### Compile Errors Function

65

66

Utility function for compiling validation results into human-readable error messages with contextual information.

67

68

```typescript { .api }

69

/**

70

* Compile validation errors into readable format with line numbers and context

71

* Re-exported from @readme/openapi-parser for convenience

72

* @param result - Validation result containing errors and warnings

73

* @returns Formatted error message string

74

*/

75

function compileErrors(result: ValidationResult): string;

76

77

interface ValidationResult {

78

valid: boolean;

79

errors: ErrorDetails[];

80

warnings: WarningDetails[];

81

}

82

83

interface ErrorDetails {

84

message: string;

85

path: string;

86

location?: {

87

line: number;

88

column: number;

89

};

90

}

91

```

92

93

**Usage Examples:**

94

95

```typescript

96

import { compileErrors } from "oas-normalize/lib/utils";

97

import { validate } from "@readme/openapi-parser";

98

99

// Manual validation and error compilation

100

const spec = {

101

openapi: "3.0.0",

102

info: { title: "API" }, // Missing version

103

paths: {}

104

};

105

106

const result = await validate(spec, { validate: { errors: { colorize: false } } });

107

108

if (!result.valid) {

109

const errorMessage = compileErrors(result);

110

console.error('Validation failed:\n', errorMessage);

111

112

// Output:

113

// OpenAPI schema validation failed.

114

//

115

// REQUIRED must have required property 'version'

116

//

117

// 2 | "info": {

118

// > 3 | "title": "API"

119

// | ^ ☹️ version is missing here!

120

// 4 | },

121

}

122

```

123

124

## Error Types and Scenarios

125

126

### Validation Errors

127

128

Most common errors thrown by OAS Normalize are validation-related:

129

130

```typescript

131

// Schema validation errors

132

const invalidSchema = {

133

openapi: "3.0.0",

134

info: { title: "API" }, // Missing required version

135

paths: {

136

"/pets/{id}": {

137

get: {

138

parameters: [

139

{

140

name: "filter", // Wrong parameter name (should be "id")

141

in: "query"

142

}

143

]

144

}

145

}

146

}

147

};

148

149

try {

150

await new OASNormalize(invalidSchema).validate();

151

} catch (error) {

152

console.log(error instanceof ValidationError); // true

153

console.log(error.name); // "ValidationError"

154

// Error message includes detailed location information

155

}

156

```

157

158

### Unsupported Format Errors

159

160

```typescript

161

const unsupportedFormat = {

162

// No swagger, openapi, or postman collection indicators

163

api: "1.0",

164

title: "Some API"

165

};

166

167

try {

168

await new OASNormalize(unsupportedFormat).validate();

169

} catch (error) {

170

console.log(error instanceof ValidationError); // true

171

console.log(error.message); // "The supplied API definition is unsupported."

172

}

173

```

174

175

### Legacy Version Errors

176

177

```typescript

178

const swagger12 = {

179

swagger: "1.2", // Unsupported legacy version

180

info: { title: "Old API" }

181

};

182

183

try {

184

await new OASNormalize(swagger12).validate();

185

} catch (error) {

186

console.log(error instanceof ValidationError); // true

187

console.log(error.message); // "Swagger v1.2 is unsupported."

188

}

189

```

190

191

### File Access Errors

192

193

```typescript

194

// Security-related errors

195

const specWithLocalRef = {

196

openapi: "3.0.0",

197

info: { title: "API", version: "1.0.0" },

198

paths: {

199

"/test": {

200

get: {

201

parameters: [{

202

schema: { $ref: "/etc/passwd" } // System file access attempt

203

}]

204

}

205

}

206

}

207

};

208

209

try {

210

await new OASNormalize(specWithLocalRef).validate();

211

} catch (error) {

212

console.log(error.message); // Contains reference resolution error

213

}

214

215

// Path access without enablePaths

216

try {

217

await new OASNormalize("./local-file.yaml").load();

218

} catch (error) {

219

console.log(error.message); // "Use `opts.enablePaths` to enable accessing local files."

220

}

221

```

222

223

## Error Message Formatting

224

225

### Colorized Output

226

227

Error messages can include ANSI color codes for terminal display:

228

229

```typescript

230

const oas = new OASNormalize(invalidSpec, { colorizeErrors: true });

231

232

try {

233

await oas.validate();

234

} catch (error) {

235

// Error message includes color codes for:

236

// - Error locations (red)

237

// - Line numbers (cyan)

238

// - Error indicators (red)

239

// - Context lines (gray)

240

console.error(error.message);

241

}

242

```

243

244

### Plain Text Output

245

246

Default error messages are plain text without color codes:

247

248

```typescript

249

const oas = new OASNormalize(invalidSpec, { colorizeErrors: false });

250

251

try {

252

await oas.validate();

253

} catch (error) {

254

// Plain text output suitable for logging or non-terminal environments

255

console.error(error.message);

256

}

257

```

258

259

## Error Handling Patterns

260

261

### Comprehensive Error Handling

262

263

```typescript

264

async function validateAPISpec(spec: any, options: Options = {}) {

265

try {

266

const oas = new OASNormalize(spec, options);

267

const result = await oas.validate();

268

269

return {

270

success: true,

271

warnings: result.warnings,

272

spec: await oas.convert() // Return normalized spec

273

};

274

275

} catch (error) {

276

if (error instanceof ValidationError) {

277

return {

278

success: false,

279

type: 'validation',

280

message: error.message,

281

details: parseErrorDetails(error.message)

282

};

283

}

284

285

// Handle other error types

286

return {

287

success: false,

288

type: 'system',

289

message: error.message,

290

error: error

291

};

292

}

293

}

294

295

function parseErrorDetails(message: string) {

296

// Extract structured information from error message

297

const lines = message.split('\n');

298

const errors = [];

299

300

// Parse contextual error information

301

// Implementation depends on specific error format needs

302

303

return errors;

304

}

305

```

306

307

### Retry Logic with Error Classification

308

309

```typescript

310

async function validateWithRetry(spec: any, maxRetries = 3) {

311

for (let attempt = 1; attempt <= maxRetries; attempt++) {

312

try {

313

const oas = new OASNormalize(spec);

314

return await oas.validate();

315

316

} catch (error) {

317

if (error instanceof ValidationError) {

318

// Don't retry validation errors - they won't change

319

throw error;

320

}

321

322

if (attempt === maxRetries) {

323

throw new Error(`Failed after ${maxRetries} attempts: ${error.message}`);

324

}

325

326

// Wait before retry (exponential backoff)

327

await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));

328

}

329

}

330

}

331

```

332

333

### Batch Processing with Error Aggregation

334

335

```typescript

336

async function validateMultipleSpecs(specs: any[]) {

337

const results = await Promise.allSettled(

338

specs.map((spec, index) =>

339

new OASNormalize(spec)

340

.validate()

341

.then(result => ({ index, success: true, result }))

342

.catch(error => ({

343

index,

344

success: false,

345

error: error instanceof ValidationError ? error : new Error(error.message)

346

}))

347

)

348

);

349

350

const successful = results.filter((r): r is PromiseFulfilledResult<any> =>

351

r.status === 'fulfilled' && r.value.success

352

);

353

354

const failed = results.filter((r): r is PromiseFulfilledResult<any> =>

355

r.status === 'fulfilled' && !r.value.success

356

);

357

358

return {

359

successful: successful.map(r => r.value),

360

failed: failed.map(r => ({

361

index: r.value.index,

362

error: r.value.error,

363

isValidationError: r.value.error instanceof ValidationError

364

})),

365

summary: {

366

total: specs.length,

367

successful: successful.length,

368

failed: failed.length

369

}

370

};

371

}

372

```

373

374

## Integration with Logging

375

376

### Structured Logging

377

378

```typescript

379

import { ValidationError } from "oas-normalize/lib/errors";

380

381

class APIValidator {

382

private logger: Logger;

383

384

async validateSpec(spec: any, context: { source: string; version?: string } = {}) {

385

try {

386

const oas = new OASNormalize(spec);

387

const result = await oas.validate();

388

389

this.logger.info('API validation successful', {

390

source: context.source,

391

version: context.version,

392

warnings: result.warnings.length

393

});

394

395

return result;

396

397

} catch (error) {

398

if (error instanceof ValidationError) {

399

this.logger.error('API validation failed', {

400

source: context.source,

401

version: context.version,

402

error: error.message,

403

type: 'validation'

404

});

405

} else {

406

this.logger.error('API validation system error', {

407

source: context.source,

408

error: error.message,

409

type: 'system'

410

});

411

}

412

413

throw error;

414

}

415

}

416

}

417

```

418

419

### Error Reporting

420

421

```typescript

422

function createErrorReport(error: ValidationError) {

423

return {

424

timestamp: new Date().toISOString(),

425

type: 'validation_error',

426

name: error.name,

427

message: error.message,

428

stack: error.stack,

429

parsed: {

430

errors: extractErrorLocations(error.message),

431

summary: extractErrorSummary(error.message)

432

}

433

};

434

}

435

436

function extractErrorLocations(message: string) {

437

// Parse line number and location information from formatted error message

438

const locationRegex = />\s*(\d+)\s*\|/g;

439

const locations = [];

440

let match;

441

442

while ((match = locationRegex.exec(message)) !== null) {

443

locations.push(parseInt(match[1]));

444

}

445

446

return locations;

447

}

448

```