How to Catch and Handle yaml-cpp Parsing Exceptions: A Complete Guide

yaml-cpp throws YAML::ParserException (derived from YAML::Exception) when encountering malformed YAML, providing location metadata via the mark member that you can catch using standard C++ try-catch blocks.

The jbeder/yaml-cpp library converts YAML streams into events or nodes through the YAML::Parser class. When the parser encounters invalid syntax, duplicate anchors, or malformed tags, it raises specific exceptions that carry precise line and column information. Understanding this exception hierarchy allows you to distinguish between parsing errors and representation errors while extracting detailed diagnostic data.

The yaml-cpp Exception Hierarchy

All yaml-cpp exceptions derive from YAML::Exception, which itself inherits from std::runtime_error. This hierarchy is defined in [include/yaml-cpp/exceptions.h](https://github.com/jbeder/yaml-cpp/blob/master/include/yaml-cpp/exceptions.h).

The inheritance chain looks like this:


YAML::Exception                ← std::runtime_error
 └─ YAML::ParserException      ← YAML::Exception
 └─ YAML::RepresentationException ← YAML::Exception
      ├─ InvalidScalar
      ├─ KeyNotFound / TypedKeyNotFound
      ├─ BadConversion / TypedBadConversion
      ├─ BadDereference
      ├─ BadSubscript
      ├─ BadPushback
      ├─ BadInsert
      └─ NonUniqueMapKey

YAML::ParserException is thrown during the tokenization and event generation phase. Representation exceptions (like BadConversion or KeyNotFound) occur later when you access or manipulate the resulting YAML::Node objects.

Where Parsing Exceptions Originate

The primary throw point is Parser::HandleNextDocument, declared in [include/yaml-cpp/parser.h](https://github.com/jbeder/yaml-cpp/blob/master/include/yaml-cpp/parser.h) (lines 55-58). When you call YAML::Load or use the streaming operator >>, the library internally invokes this method, which may throw if the input violates the YAML specification.

The concrete exception construction happens in [src/singleparser.cpp](https://github.com/jbeder/yaml-cpp/blob/master/src/singleparser.cpp), where the tokenizer detects invalid tokens. Representation errors are generated in [src/node/node.cpp](https://github.com/jbeder/yaml-cpp/blob/master/src/node/node.cpp) when node access operations fail.

Catching yaml-cpp Exceptions in Practice

You can catch exceptions using either the high-level YAML::Load API or the low-level Parser interface. Both approaches throw the same exception types.

High-Level API with YAML::Load

The YAML::Load function internally constructs a Parser and processes the stream. Wrap this call to catch syntax errors:

#include <fstream>
#include <iostream>
#include <yaml-cpp/yaml.h>

int main() {
    std::ifstream fin("config.yaml");
    if (!fin) {
        std::cerr << "Could not open config.yaml\n";
        return 1;
    }

    try {
        // Parser invoked implicitly by the Load function
        YAML::Node cfg = YAML::Load(fin);
        std::cout << "Version: " << cfg["version"].as<std::string>() << '\n';
    }
    catch (const YAML::ParserException& ex) {
        // Specific handling for syntax errors
        std::cerr << "Parsing error: " << ex.what() << '\n';
        std::cerr << "  at line " << ex.mark.line + 1
                  << ", column " << ex.mark.column + 1 << '\n';
        return 1;
    }
    catch (const YAML::Exception& ex) {
        // Catches all other yaml-cpp errors (representation, conversion, etc.)
        std::cerr << "YAML error: " << ex.what() << '\n';
        return 1;
    }
    catch (const std::exception& ex) {
        // Fallback for standard library exceptions
        std::cerr << "Unexpected error: " << ex.what() << '\n';
        return 1;
    }

    return 0;
}

Low-Level Parser API

For event-driven parsing, instantiate YAML::Parser directly and call HandleNextDocument:

#include <fstream>
#include <yaml-cpp/parser.h>
#include <yaml-cpp/eventhandler.h>

int main() {
    std::ifstream fin("data.yaml");
    YAML::Parser parser(fin);
    YAML::NodeBuilder builder;  // implements EventHandler
    
    try {
        while (parser.HandleNextDocument(builder)) {
            YAML::Node doc = builder.GetRootNode();
            // Process document...
        }
    }
    catch (const YAML::ParserException& e) {
        std::cerr << "Parse failure: " << e.what() << '\n';
        std::cerr << "Location: line " << e.mark.line + 1 << '\n';
    }
}

Accessing Error Location and Messages

Every YAML::Exception contains a YAML::Mark object recording the exact error position. According to the implementation in exceptions.h, the exception message is constructed by Exception::build_what and includes the line and column.

To extract diagnostic information:

  • e.what(): Returns the complete error message including filename (if available), line, column, and description.
  • e.mark.line: Zero-indexed line number where the error occurred.
  • e.mark.column: Zero-indexed column number.

Since indices are zero-based, add 1 when displaying to users for readability.

Summary

  • yaml-cpp throws YAML::ParserException during tokenization and YAML::RepresentationException during node access.
  • The exception hierarchy is rooted in YAML::Exception (defined in include/yaml-cpp/exceptions.h), allowing you to catch all yaml-cpp errors with a single handler or specialize for specific failure types.
  • Location data is available via the mark member, providing line and column integers.
  • Primary throw point is Parser::HandleNextDocument in include/yaml-cpp/parser.h, invoked by both high-level YAML::Load and manual parsing loops.

Frequently Asked Questions

What is the base class for all yaml-cpp exceptions?

YAML::Exception is the abstract base class for all yaml-cpp errors, inheriting from std::runtime_error. It is defined in include/yaml-cpp/exceptions.h. Catching this base class will handle ParserException, RepresentationException, and all their derivatives like BadConversion or KeyNotFound.

How do I get the line number where a YAML parsing error occurred?

Access the mark member of the caught exception. This YAML::Mark struct contains line and column members (zero-indexed). For example: ex.mark.line + 1 gives the human-readable line number. This data is populated by the parser in src/singleparser.cpp and propagated through the exception hierarchy.

Should I catch YAML::ParserException or YAML::Exception?

Catch YAML::ParserException if you only need to handle syntax errors (malformed YAML, invalid tags, duplicate anchors). Catch YAML::Exception if you want to handle all yaml-cpp failures including type conversion errors (BadConversion) and missing keys (KeyNotFound). For complete safety, catch YAML::Exception first, then std::exception.

Why does yaml-cpp use exceptions instead of error codes?

The library uses C++ exceptions to separate error handling from normal control flow, consistent with the C++ standard library approach. The Parser class throws ParserException immediately upon detecting invalid tokens in src/singleparser.cpp, preventing invalid state propagation. This design allows you to use RAII for resource cleanup while centralizing error handling in catch blocks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →