AtsushiSakai/PythonRobotics · error · ValueError

{root.name} Control node must have children

Error message

{root.name} Control node must have children

What it means

Raised by BehaviorTree XML builder's build_node when a control-node tag (sequence, selector, while-do-else) contains no child elements. Control nodes need children to execute, so an empty tag in the XML is a structural error.

Source

Thrown at MissionPlanning/BehaviorTree/behavior_tree.py:627

                )
        """
        self.node_builders[node_name] = builder

    def build_node(self, node):
        """
        Build a node from an XML element.

        Args:
            node (Element): The XML element to build the node from.

        Returns:
            BehaviorTree Node: the built node
        """
        if node.tag in self.node_builders:
            root = self.node_builders[node.tag](node)
            if root.type == NodeType.CONTROL_NODE:
                if len(node) <= 0:
                    raise ValueError(f"{root.name} Control node must have children")
                for child in node:
                    root.children.append(self.build_node(child))
            elif root.type == NodeType.DECORATOR_NODE:
                if len(node) != 1:
                    raise ValueError(
                        f"{root.name} Decorator node must have exactly one child"
                    )
                root.child = self.build_node(node[0])
            elif root.type == NodeType.ACTION_NODE:
                if len(node) != 0:
                    raise ValueError(f"{root.name} Action node must have no children")
            return root
        else:
            raise ValueError(f"Unknown node type: {node.tag}")

    def build_tree(self, xml_string):
        """
        Build a behavior tree from an XML string.

View on GitHub (pinned to 1fe4fb980f)

Solutions

  1. Add at least one child element inside the control tag in the XML.
  2. Validate the XML against your tree schema before build_tree.
  3. Check for self-closing control tags (<Sequence .../>).

Example fix

<!-- before -->
<Sequence name="s"/>

<!-- after -->
<Sequence name="s">
  <ActionA name="a"/>
</Sequence>
Defensive patterns

Strategy: validation

Validate before calling

import xml.etree.ElementTree as ET
root = ET.fromstring(xml_string)
for el in root.iter():
    if el.tag in CONTROL_TAGS and len(el) == 0:
        raise ValueError(f'{el.tag} {el.get("name")} has no children')

Try / catch

try:
    tree = builder.build_tree(xml_string)
except ValueError as e:
    if 'must have children' in str(e):
        fix_and_retry(xml_string)
    raise

Prevention

When it happens

Trigger: Parsing XML like <Sequence name="s"/> or <Sequence name="s"></Sequence> with build_tree/build_node.

Common situations: Hand-written or template-generated XML tree files where a control tag is left empty or children are commented out.

Related errors


AI-assisted analysis of AtsushiSakai/PythonRobotics@1fe4fb980f (2026-08-28). Data as JSON: /api/errors/b8b3d59c4db6ca41. Report an issue: GitHub.