# How to Check YAML Node Types (IsScalar, IsSequence, IsMap) in yaml-cpp

> Learn to check YAML node types IsScalar, IsSequence, and IsMap using yaml-cpp. This guide explains how to inspect your YAML data efficiently.

- Repository: [Jesse Beder/yaml-cpp](https://github.com/jbeder/yaml-cpp)
- Tags: how-to-guide
- Published: 2026-07-11

---

**The yaml-cpp library provides three lightweight query methods—`IsScalar()`, `IsSequence()`, and `IsMap()`—that inspect a node's internal `NodeType` to determine whether it holds a single value, an ordered list, or a key-value mapping.**

When parsing YAML documents with the jbeder/yaml-cpp library, you must determine the structural type of each `Node` before accessing its data. These type checks are implemented as simple enum comparisons in [`include/yaml-cpp/node/node.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/node.h), offering zero-cost verification that guards against invalid conversions.

## Understanding the NodeType Enumeration

yaml-cpp represents every parsed YAML construct as a `Node` object that internally stores a **NodeType** value. This enumeration defines three distinct categories:

- **Scalar** – Single values such as strings, integers, floats, or booleans
- **Sequence** – Ordered lists (YAML arrays)
- **Map** – Associative collections of key-value pairs (YAML mappings)

The `NodeType` enum is defined within the `Node` class implementation in [`include/yaml-cpp/node/node.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/node.h). When you load a document using `YAML::Load()`, each node in the resulting hierarchy carries one of these type markers.

## Checking Node Types with Query Methods

The `Node` class exposes three boolean query methods that compare the stored `NodeType` against the corresponding enum value. These methods are defined at lines 56-58 of [`include/yaml-cpp/node/node.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/node.h):

```cpp
bool IsScalar()   const { return Type() == NodeType::Scalar; }
bool IsSequence() const { return Type() == NodeType::Sequence; }
bool IsMap()      const { return Type() == NodeType::Map; }

```

Each method calls the internal `Type()` accessor and performs a direct equality comparison. This design provides **zero-cost type queries** with no dynamic casting or exception handling overhead.

### Usage in Conversion Utilities

The library uses these guards throughout [`include/yaml-cpp/node/convert.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/convert.h) to validate node shapes before extracting values. For example, conversion functions typically check `if (!node.IsScalar())` before attempting to parse scalar data, throwing `BadConversion` when the type check fails.

## Practical Examples for Type Checking

### Detecting and Extracting Scalars

Before converting a node to a specific type, verify it contains a scalar value:

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

double getDouble(const YAML::Node& n) {
    // Guard against non-scalar nodes before extraction
    if (!n.IsScalar()) {
        throw YAML::BadConversion(n, "expected scalar for double");
    }
    return n.as<double>();
}

int main() {
    YAML::Node root = YAML::Load("value: 3.14");
    
    if (root["value"].IsScalar()) {
        std::cout << "Scalar: " << root["value"].as<double>() << "\n";
    }
}

```

### Iterating Over Sequence Nodes

Use `IsSequence()` to safely access array elements:

```cpp
YAML::Node node = YAML::Load("[1, 2, 3]");

if (node.IsSequence()) {
    std::cout << "Sequence size: " << node.size() << "\n";
    for (std::size_t i = 0; i < node.size(); ++i) {
        std::cout << "  - " << node[i].as<int>() << "\n";
    }
}

```

### Traversing Map Nodes

Check for associative structures before iterating:

```cpp
YAML::Node config = YAML::Load(R"(
    database:
        host: localhost
        port: 5432
)");

if (config["database"].IsMap()) {
    for (auto it = config["database"].begin(); it != config["database"].end(); ++it) {
        std::cout << it->first.as<std::string>() 
                  << ": " << it->second.as<std::string>() << "\n";
    }
}

```

## Testing and Validation

The test suite in [`test/node/node_test.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/test/node/node_test.cpp) exercises these type queries across various YAML constructs. For instance, the suite verifies that a loaded sequence correctly identifies as such:

```cpp
YAML::Node node = YAML::Load("[1, 2, 3]");
EXPECT_TRUE(node.IsSequence());  // Validates sequence detection

```

These tests ensure that `IsScalar()`, `IsSequence()`, and `IsMap()` behave consistently regardless of how the YAML document was constructed or loaded.

## Summary

- **Type Safety**: Use `IsScalar()`, `IsSequence()`, and `IsMap()` from [`include/yaml-cpp/node/node.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/node.h) to verify node structure before access
- **Zero Overhead**: These methods perform simple enum comparisons with no dynamic casting
- **Defensive Programming**: Conversion utilities in [`include/yaml-cpp/node/convert.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/convert.h) rely on these checks to throw `BadConversion` on type mismatches
- **Comprehensive Coverage**: The `NodeType` enum covers all three fundamental YAML constructs, enabling complete document traversal

## Frequently Asked Questions

### What happens if I call `as<T>()` without checking the node type first?

The conversion will attempt to proceed, but if the node's `NodeType` does not match the requested conversion (for example, calling `as<std::string>()` on a Sequence), the library throws `YAML::BadConversion`. While the library does not require explicit type checks, using `IsScalar()`, `IsSequence()`, or `IsMap()` before conversion prevents exceptions and makes intent explicit.

### Can a node be more than one type simultaneously?

No. According to the implementation in [`include/yaml-cpp/node/node.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/node.h), each `Node` maintains exactly one `NodeType` value. A node cannot be both a Scalar and a Map, or both a Sequence and a Scalar. The type is determined during parsing and remains fixed for the lifetime of the node object.

### Are these type-checking methods thread-safe?

Yes. The `IsScalar()`, `IsSequence()`, and `IsMap()` methods are `const` member functions that only read the node's internal type identifier. Since they do not modify state and the `NodeType` is immutable after construction, these checks are safe to call from multiple threads on the same node instance.

### How do I check if a node exists before checking its type?

Use the `operator[]` or `operator()` accessors first, as they return a valid `Node` object even for missing keys. Check if the node is defined (non-null) using `if (node)` or `if (!node.IsNull())` before calling `IsScalar()`, `IsSequence()`, or `IsMap()`. Undefined nodes may report unexpected type behavior, so always verify existence before inspecting the type.