netdata/netdata · error · ConstructorError

expected a mapping for merging, but found %s

Error message

expected a mapping for merging, but found %s

What it means

Raised by SafeConstructor.flatten_mapping while processing a merge key ('<<'). When the merge value is a sequence, each element must itself be a mapping; an element that is a scalar or another sequence raises this error with the offending subnode's mark.

Source

Thrown at src/collectors/python.d.plugin/python_modules/pyyaml3/constructor.py:181

                if key_node.tag == 'tag:yaml.org,2002:value':
                    return self.construct_scalar(value_node)
        return super().construct_scalar(node)

    def flatten_mapping(self, node):
        merge = []
        index = 0
        while index < len(node.value):
            key_node, value_node = node.value[index]
            if key_node.tag == 'tag:yaml.org,2002:merge':
                del node.value[index]
                if isinstance(value_node, MappingNode):
                    self.flatten_mapping(value_node)
                    merge.extend(value_node.value)
                elif isinstance(value_node, SequenceNode):
                    submerge = []
                    for subnode in value_node.value:
                        if not isinstance(subnode, MappingNode):
                            raise ConstructorError("while constructing a mapping",
                                    node.start_mark,
                                    "expected a mapping for merging, but found %s"
                                    % subnode.id, subnode.start_mark)
                        self.flatten_mapping(subnode)
                        submerge.append(subnode.value)
                    submerge.reverse()
                    for value in submerge:
                        merge.extend(value)
                else:
                    raise ConstructorError("while constructing a mapping", node.start_mark,
                            "expected a mapping or list of mappings for merging, but found %s"
                            % value_node.id, value_node.start_mark)
            elif key_node.tag == 'tag:yaml.org,2002:value':
                key_node.tag = 'tag:yaml.org,2002:str'
                index += 1
            else:
                index += 1
        if merge:

View on GitHub (pinned to 4864de85e2)

Solutions

  1. Make every element of the merge list a mapping: '<<: [{a: 1}, {b: 2}]'.
  2. Remove non-mapping entries from the merge sequence.
  3. If merging one mapping only, drop the list brackets: '<<: *defaults'.

Example fix

# before
base: &base {a: 1}
merged:
  <<: [*base, extra]

# after
base: &base {a: 1}
extra: &extra {b: 2}
merged:
  <<: [*base, *extra]
Defensive patterns

Strategy: validation

Validate before calling

import yaml

def merge_list_elements_are_mappings(text):
    for n in iter_all_nodes(yaml.compose(text)):
        if isinstance(n, yaml.MappingNode):
            for k, v in n.value:
                if k.tag == 'tag:yaml.org,2002:merge' and isinstance(v, yaml.SequenceNode):
                    for sub in v.value:
                        if not isinstance(sub, yaml.MappingNode):
                            raise ValueError('merge list has a non-mapping %s at line %s' % (sub.id, sub.start_mark.line))

Try / catch

try:
    cfg = yaml.safe_load(text)
except yaml.ConstructorError as e:
    if 'expected a mapping for merging' in str(e):
        reject_config('every entry in a <<: merge list must be a mapping, line %s' % e.problem_mark.line)

Prevention

When it happens

Trigger: '<<: [{a: 1}, not-a-map]' — a list under the merge key containing a scalar/nested list; mixing mappings and plain values in a merge list.

Common situations: Users building inheritance-style configs with '<<:' and appending a stray scalar (e.g. a comment value or a flag) into the merge list; copy-paste errors in templated YAML.

Related errors


AI-assisted analysis of netdata/netdata@4864de85e2 (2026-08-15). Data as JSON: /api/errors/6e57ec3542c67669. Report an issue: GitHub.