or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

customization.mddumping-serialization.mderror-handling.mdindex.mdloaders-dumpers.mdloading-parsing.mdsafe-operations.md

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive exception hierarchy for handling different types of YAML processing errors with detailed position information. PyYAML provides specific exception types for each processing stage, enabling precise error handling and debugging.

3

4

## Capabilities

5

6

### Base Exception Classes

7

8

Foundation exception classes that other YAML errors inherit from.

9

10

```python { .api }

11

class YAMLError(Exception):

12

"""

13

Base exception class for all YAML errors.

14

15

All PyYAML-specific exceptions inherit from this class, making it easy

16

to catch any YAML-related error.

17

"""

18

19

class MarkedYAMLError(YAMLError):

20

"""

21

Exception with position information in the YAML stream.

22

23

Attributes:

24

context (str): Context where the error occurred

25

context_mark (Mark): Position of the context

26

problem (str): Description of the problem

27

problem_mark (Mark): Position where the problem was detected

28

note (str): Additional notes about the error

29

"""

30

```

31

32

### Processing Stage Errors

33

34

Specific exception types for each stage of YAML processing.

35

36

```python { .api }

37

class ReaderError(YAMLError):

38

"""

39

Errors during input stream reading.

40

41

Raised when there are issues with:

42

- Character encoding detection or conversion

43

- Invalid Unicode sequences

44

- I/O errors reading from streams

45

"""

46

47

class ScannerError(MarkedYAMLError):

48

"""

49

Errors during lexical analysis (scanning).

50

51

Raised when the scanner encounters:

52

- Invalid character sequences

53

- Malformed YAML syntax at the character level

54

- Unclosed quotes or brackets

55

"""

56

57

class ParserError(MarkedYAMLError):

58

"""

59

Errors during syntactic analysis (parsing).

60

61

Raised when the parser encounters:

62

- Invalid YAML document structure

63

- Malformed block or flow constructs

64

- Inconsistent indentation

65

"""

66

67

class ComposerError(MarkedYAMLError):

68

"""

69

Errors during tree composition.

70

71

Raised when composing the representation tree:

72

- Duplicate anchor names

73

- Invalid alias references

74

- Circular references

75

"""

76

77

class ConstructorError(MarkedYAMLError):

78

"""

79

Errors during object construction.

80

81

Raised when constructing Python objects:

82

- Unknown or invalid YAML tags

83

- Type conversion failures

84

- Security restrictions violated

85

"""

86

87

class RepresenterError(YAMLError):

88

"""

89

Errors during object representation.

90

91

Raised when representing Python objects:

92

- Objects that cannot be represented

93

- Circular references in data structures

94

- Type representation conflicts

95

"""

96

97

class EmitterError(YAMLError):

98

"""

99

Errors during YAML text emission.

100

101

Raised when emitting YAML:

102

- I/O errors writing to streams

103

- Encoding issues

104

- Invalid emitter state

105

"""

106

107

class SerializerError(YAMLError):

108

"""

109

Errors during tree serialization.

110

111

Raised when serializing representation trees:

112

- Invalid node structures

113

- Serialization state conflicts

114

"""

115

```

116

117

### Position Tracking

118

119

Detailed position information for debugging YAML syntax errors.

120

121

```python { .api }

122

class Mark:

123

"""

124

Represents a position in the YAML stream.

125

126

Attributes:

127

name (str): Name of the input source (filename, etc.)

128

index (int): Character index in the stream

129

line (int): Line number (0-based)

130

column (int): Column number (0-based)

131

buffer (str): Buffer content around the position

132

pointer (int): Pointer position in the buffer

133

"""

134

135

def get_snippet(self, indent=4, max_length=75):

136

"""

137

Get a snippet of the input around this position.

138

139

Args:

140

indent (int): Number of spaces to indent the snippet

141

max_length (int): Maximum length of the snippet

142

143

Returns:

144

str: Formatted snippet showing the error location

145

"""

146

```

147

148

## Usage Examples

149

150

### Basic Error Handling

151

152

```python

153

import yaml

154

155

def safe_load_yaml(content):

156

"""Safely load YAML with comprehensive error handling."""

157

try:

158

return yaml.safe_load(content)

159

except yaml.YAMLError as e:

160

print(f"YAML Error: {e}")

161

return None

162

except Exception as e:

163

print(f"Unexpected error: {e}")

164

return None

165

166

# Test with various error conditions

167

test_cases = [

168

"valid: yaml", # Valid YAML

169

"invalid: [unclosed list", # ScannerError

170

"duplicate: key\nduplicate: key", # ComposerError (in some contexts)

171

"invalid:\n - item\n not_aligned", # ParserError

172

]

173

174

for i, content in enumerate(test_cases):

175

print(f"Test {i + 1}: {safe_load_yaml(content)}")

176

```

177

178

### Detailed Error Information

179

180

```python

181

import yaml

182

183

yaml_content = """

184

name: John Doe

185

items:

186

- item1

187

- item2

188

- nested # Invalid indentation

189

"""

190

191

try:

192

data = yaml.safe_load(yaml_content)

193

except yaml.MarkedYAMLError as e:

194

print(f"Error Type: {type(e).__name__}")

195

print(f"Problem: {e.problem}")

196

197

if e.problem_mark:

198

mark = e.problem_mark

199

print(f"Position: Line {mark.line + 1}, Column {mark.column + 1}")

200

print(f"Character index: {mark.index}")

201

202

# Show snippet if available

203

snippet = mark.get_snippet()

204

if snippet:

205

print("Context:")

206

print(snippet)

207

208

if e.context:

209

print(f"Context: {e.context}")

210

if e.context_mark:

211

ctx_mark = e.context_mark

212

print(f"Context position: Line {ctx_mark.line + 1}, Column {ctx_mark.column + 1}")

213

214

except yaml.YAMLError as e:

215

print(f"YAML Error: {e}")

216

```

217

218

### Specific Error Type Handling

219

220

```python

221

import yaml

222

223

def load_config_file(filename):

224

"""Load configuration with specific error handling."""

225

try:

226

with open(filename, 'r') as f:

227

return yaml.safe_load(f)

228

229

except FileNotFoundError:

230

print(f"Configuration file not found: {filename}")

231

return {}

232

233

except yaml.ReaderError as e:

234

print(f"File encoding error in {filename}: {e}")

235

return None

236

237

except yaml.ScannerError as e:

238

print(f"YAML syntax error in {filename}:")

239

print(f" Problem: {e.problem}")

240

if e.problem_mark:

241

print(f" Line {e.problem_mark.line + 1}, Column {e.problem_mark.column + 1}")

242

return None

243

244

except yaml.ParserError as e:

245

print(f"YAML structure error in {filename}:")

246

print(f" Problem: {e.problem}")

247

if e.problem_mark:

248

print(f" Line {e.problem_mark.line + 1}, Column {e.problem_mark.column + 1}")

249

return None

250

251

except yaml.ConstructorError as e:

252

print(f"YAML construction error in {filename}:")

253

print(f" Problem: {e.problem}")

254

if e.problem_mark:

255

print(f" Line {e.problem_mark.line + 1}, Column {e.problem_mark.column + 1}")

256

return None

257

258

except yaml.YAMLError as e:

259

print(f"Other YAML error in {filename}: {e}")

260

return None

261

262

# Usage

263

config = load_config_file('app.yaml')

264

if config is not None:

265

print("Configuration loaded successfully")

266

```

267

268

### Custom Error Handling in Constructors

269

270

```python

271

import yaml

272

from datetime import datetime

273

274

def strict_datetime_constructor(loader, node):

275

"""Strict datetime constructor with custom error handling."""

276

try:

277

value = loader.construct_scalar(node)

278

return datetime.fromisoformat(value)

279

except ValueError as e:

280

# Convert to ConstructorError with position info

281

raise yaml.ConstructorError(

282

None, None,

283

f"Invalid datetime format: {e}",

284

node.start_mark

285

)

286

287

yaml.add_constructor('!datetime', strict_datetime_constructor)

288

289

yaml_content = """

290

created: !datetime 2023-01-01T10:00:00

291

invalid: !datetime not-a-date

292

"""

293

294

try:

295

data = yaml.load(yaml_content, yaml.Loader)

296

except yaml.ConstructorError as e:

297

print(f"Constructor error: {e.problem}")

298

if e.problem_mark:

299

print(f"At line {e.problem_mark.line + 1}, column {e.problem_mark.column + 1}")

300

```

301

302

### Validation with Error Context

303

304

```python

305

import yaml

306

307

class ValidatingLoader(yaml.SafeLoader):

308

"""Loader that validates data structure during construction."""

309

pass

310

311

def validated_mapping_constructor(loader, node):

312

"""Construct mapping with validation."""

313

# First construct normally

314

mapping = loader.construct_mapping(node, deep=True)

315

316

# Then validate

317

if 'name' not in mapping:

318

raise yaml.ConstructorError(

319

"while constructing a validated mapping", node.start_mark,

320

"missing required field 'name'", node.start_mark

321

)

322

323

if not isinstance(mapping.get('age'), int):

324

raise yaml.ConstructorError(

325

"while constructing a validated mapping", node.start_mark,

326

"field 'age' must be an integer", node.start_mark

327

)

328

329

return mapping

330

331

ValidatingLoader.add_constructor('!person', validated_mapping_constructor)

332

333

yaml_content = """

334

person1: !person

335

name: John

336

age: 30

337

338

person2: !person

339

name: Jane

340

age: "not a number" # This will cause an error

341

"""

342

343

try:

344

data = yaml.load(yaml_content, ValidatingLoader)

345

except yaml.ConstructorError as e:

346

print(f"Validation error: {e.problem}")

347

print(f"Context: {e.context}")

348

if e.problem_mark:

349

print(f"Position: Line {e.problem_mark.line + 1}")

350

```

351

352

## Error Recovery Strategies

353

354

### Partial Loading

355

356

```python

357

import yaml

358

359

def load_yaml_partially(content):

360

"""Load YAML documents, skipping invalid ones."""

361

documents = []

362

errors = []

363

364

try:

365

for doc in yaml.safe_load_all(content):

366

documents.append(doc)

367

except yaml.YAMLError as e:

368

errors.append(e)

369

370

return documents, errors

371

372

multi_doc_yaml = """

373

---

374

valid: document1

375

---

376

invalid: [unclosed

377

---

378

valid: document3

379

"""

380

381

docs, errs = load_yaml_partially(multi_doc_yaml)

382

print(f"Loaded {len(docs)} documents, {len(errs)} errors")

383

```

384

385

### Fallback Loading

386

387

```python

388

import yaml

389

390

def load_with_fallback(content):

391

"""Try different loaders in order of safety."""

392

loaders = [yaml.SafeLoader, yaml.FullLoader, yaml.Loader]

393

394

for loader_class in loaders:

395

try:

396

return yaml.load(content, Loader=loader_class), loader_class.__name__

397

except yaml.ConstructorError:

398

continue # Try next loader

399

except yaml.YAMLError:

400

break # Syntax error, don't try other loaders

401

402

return None, None

403

404

# YAML with Python-specific tag

405

yaml_content = """

406

data: !!python/tuple [1, 2, 3]

407

"""

408

409

result, loader_used = load_with_fallback(yaml_content)

410

if result:

411

print(f"Loaded successfully with {loader_used}")

412

else:

413

print("Failed to load with any loader")

414

```

415

416

## Debugging Techniques

417

418

### Verbose Error Reporting

419

420

```python

421

import yaml

422

import traceback

423

424

def debug_yaml_load(content, filename="<string>"):

425

"""Load YAML with detailed debugging information."""

426

try:

427

return yaml.safe_load(content)

428

except yaml.MarkedYAMLError as e:

429

print(f"=== YAML Error in {filename} ===")

430

print(f"Error Type: {type(e).__name__}")

431

print(f"Problem: {e.problem}")

432

433

if e.problem_mark:

434

mark = e.problem_mark

435

print(f"Position: Line {mark.line + 1}, Column {mark.column + 1}")

436

437

# Show context lines

438

lines = content.split('\n')

439

start_line = max(0, mark.line - 2)

440

end_line = min(len(lines), mark.line + 3)

441

442

print("\nContext:")

443

for i in range(start_line, end_line):

444

prefix = ">>> " if i == mark.line else " "

445

print(f"{prefix}{i + 1:3}: {lines[i]}")

446

if i == mark.line:

447

print(f" {' ' * (3 + mark.column)}^")

448

449

print(f"\nPython traceback:")

450

traceback.print_exc()

451

return None

452

453

except Exception as e:

454

print(f"Unexpected error: {e}")

455

traceback.print_exc()

456

return None

457

458

# Test with error

459

debug_yaml_load("""

460

name: John

461

items:

462

- one

463

- two

464

- invalid indentation

465

""")

466

```

467

468

### Processing Stage Identification

469

470

```python

471

import yaml

472

473

def identify_processing_stage(content):

474

"""Identify which processing stage fails."""

475

try:

476

# Test scanning

477

list(yaml.scan(content, yaml.SafeLoader))

478

print("✓ Scanning successful")

479

480

# Test parsing

481

list(yaml.parse(content, yaml.SafeLoader))

482

print("✓ Parsing successful")

483

484

# Test composition

485

yaml.compose(content, yaml.SafeLoader)

486

print("✓ Composition successful")

487

488

# Test construction

489

yaml.safe_load(content)

490

print("✓ Construction successful")

491

492

except yaml.ScannerError as e:

493

print(f"✗ Scanning failed: {e.problem}")

494

except yaml.ParserError as e:

495

print(f"✗ Parsing failed: {e.problem}")

496

except yaml.ComposerError as e:

497

print(f"✗ Composition failed: {e.problem}")

498

except yaml.ConstructorError as e:

499

print(f"✗ Construction failed: {e.problem}")

500

501

# Test problematic YAML

502

identify_processing_stage("invalid: [unclosed")

503

```

504

505

## Best Practices

506

507

### Error Handling Guidelines

508

509

1. **Always handle YAMLError** as the base exception type

510

2. **Use specific exception types** when you need different handling

511

3. **Check for position information** to provide better error messages

512

4. **Validate data after loading** rather than relying solely on YAML validation

513

5. **Provide meaningful error messages** to users

514

515

### Production Error Handling

516

517

1. **Log errors with context** for debugging

518

2. **Provide fallback behavior** for non-critical failures

519

3. **Sanitize error messages** before showing to users

520

4. **Monitor error patterns** to identify common issues

521

5. **Have recovery strategies** for partial failures

522

523

### Development and Testing

524

525

1. **Test error conditions** explicitly in unit tests

526

2. **Use debug modes** during development

527

3. **Validate error message quality** and usefulness

528

4. **Test with malformed input** to ensure robustness

529

5. **Document expected error scenarios** for API users