From 13a83703d603f1eab9fe26cf03c5102a7641f44f Mon Sep 17 00:00:00 2001 From: wuyangfan <1102042793@qq.com> Date: Tue, 26 May 2026 23:18:56 +0800 Subject: [PATCH] docs: document exception handling for the node API Add Error-Handling.md covering ParserException, conversion errors, optional map keys (operator[] does not throw KeyNotFound), and emitter failures. Link from README and Tutorial. Fixes #1395 Refs #594, #1122 --- README.md | 2 + docs/Error-Handling.md | 89 ++++++++++++++++++++++++++++++++++++++++++ docs/Tutorial.md | 6 ++- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 docs/Error-Handling.md diff --git a/README.md b/README.md index 285644ed7..01173cc03 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ See [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) and [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML) for reference. For the old API (until 0.5.0), see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)). +For exceptions, optional keys, and `.as()` conversion errors, see [Error handling](docs/Error-Handling.md) in this repository. + ## Any Problems? If you find a bug, post an [issue](https://github.com/jbeder/yaml-cpp/issues)! If you have questions about how to use yaml-cpp, please post it on http://stackoverflow.com and tag it [`yaml-cpp`](http://stackoverflow.com/questions/tagged/yaml-cpp). diff --git a/docs/Error-Handling.md b/docs/Error-Handling.md new file mode 100644 index 000000000..765830240 --- /dev/null +++ b/docs/Error-Handling.md @@ -0,0 +1,89 @@ +# Error handling and exceptions + +yaml-cpp reports failures by throwing C++ exceptions. The types are declared in [`include/yaml-cpp/exceptions.h`](../include/yaml-cpp/exceptions.h). All public exceptions derive from `YAML::Exception` (which derives from `std::runtime_error`) and expose a `mark` member when the error is tied to a location in the input document. + +This page describes the exceptions you can rely on when using the **current node API** (`YAML::Load`, `YAML::Node`, `.as()`, etc.). Catching `YAML::Exception` is sufficient for most applications. + +## Parsing and I/O + +| Exception | When it is thrown | +|-----------|-------------------| +| `ParserException` | The input is not valid YAML (syntax, structure, directives, etc.) during `YAML::Load`, `YAML::LoadFile`, or streaming parse. `what()` includes line/column when `mark` is set. | +| `BadFile` | `YAML::LoadFile` cannot open or read the given path. | + +Example: + +```cpp +try { + YAML::Node doc = YAML::LoadFile("config.yaml"); +} catch (const YAML::ParserException& e) { + // malformed YAML — e.mark.line / e.mark.column are 0-based + std::cerr << e.what() << "\n"; +} catch (const YAML::BadFile& e) { + std::cerr << "cannot read file: " << e.what() << "\n"; +} +``` + +## Optional map keys (no exception) + +`operator[]` on a map **does not** throw when a key is missing. It returns a node that evaluates to false in a boolean context (see the [Tutorial](Tutorial.md)). Use that for optional fields: + +```cpp +YAML::Node config = YAML::LoadFile("config.yaml"); + +if (config["lastLogin"]) { + auto t = config["lastLogin"].as(); +} + +// This does NOT throw KeyNotFound: +YAML::Node missing = config["notpresentkey"]; +``` + +`YAML::KeyNotFound` is defined in the public headers for historical/API reasons, but the current node implementation does **not** throw it for missing map keys. Prefer `if (node["key"])` (or `node[key]` with a defined node) before calling `.as()`. + +## Type conversion and node misuse + +| Exception | When it is thrown | +|-----------|-------------------| +| `BadConversion` | Generic conversion failure from `.as()`. | +| `TypedBadConversion` | Same as `BadConversion`, thrown by `.as()` when the scalar cannot be converted to `T` (wrong type, out of range, etc.). | +| `InvalidNode` | Using a node incorrectly: e.g. `.as()` on an undefined node, wrong iterator use, invalid key path. Message may include the first invalid key when available. | +| `BadSubscript` | `operator[]` used on a **scalar** node (not a map/sequence). | +| `BadPushback` | `push_back` on a non-sequence node. | +| `BadInsert` | `insert` on a node that cannot behave as a map. | +| `BadDereference` | Dereferencing an invalid node (rare in normal use). | +| `NonUniqueMapKey` | Inserting a duplicate key into a map node. | + +Example (user-provided config with wrong types): + +```cpp +try { + YAML::Node doc = YAML::LoadFile("user.yaml"); + if (!doc["port"]) { + throw std::runtime_error("missing required key: port"); + } + unsigned port = doc["port"].as(); +} catch (const YAML::TypedBadConversion& e) { + std::cerr << "port is not a valid unsigned integer: " << e.what() << "\n"; +} catch (const YAML::RepresentationException& e) { + std::cerr << "config node error: " << e.what() << "\n"; +} catch (const YAML::ParserException& e) { + std::cerr << "invalid YAML: " << e.what() << "\n"; +} +``` + +`RepresentationException` is the common base for conversion and node-operation errors listed above (except `ParserException` and `BadFile`). + +## Emitting YAML + +| Exception | When it is thrown | +|-----------|-------------------| +| `EmitterException` | Invalid emitter state or output (e.g. via `YAML::Emitter` / stream output). | + +## Internal errors + +Some code paths may throw `std::runtime_error` with messages like `yaml-cpp: internal error`. These indicate an internal inconsistency and are **not** part of the documented user-facing contract. Please report them as bugs. + +## Related issues + +This document addresses long-standing requests for clearer error-handling guidance ([#594](https://github.com/jbeder/yaml-cpp/issues/594), [#1122](https://github.com/jbeder/yaml-cpp/issues/1122), [#1395](https://github.com/jbeder/yaml-cpp/issues/1395)). diff --git a/docs/Tutorial.md b/docs/Tutorial.md index a7b0e21d0..d33a6b338 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -198,4 +198,8 @@ Then you could use `Vec3` wherever you could use any other type: YAML::Node node = YAML::Load("start: [1, 3, 0]"); Vec3 v = node["start"].as(); node["end"] = Vec3(2, -1, 0); -``` \ No newline at end of file +``` + +# Error handling # + +Parsing failures, file I/O errors, bad type conversions, and invalid node operations throw exceptions derived from `YAML::Exception`. Missing map keys are **not** errors: use `if (node["key"])` before `.as()`. See [Error handling](Error-Handling.md) for the full list of exception types and examples. \ No newline at end of file