run-llama/llama_index · error · ValueError

Child objects must be a list of RelatedNodeInfo objects.

Error message

Child objects must be a list of RelatedNodeInfo objects.

What it means

TextNode.child_nodes reads relationships[NodeRelationship.CHILD] and, opposite to the singular relations, requires a list of RelatedNodeInfo. CHILD is the only plural relationship in the schema; a single RelatedNodeInfo or dict raises ValueError.

Source

Thrown at llama-index-core/llama_index/core/schema.py:447

    def parent_node(self) -> Optional[RelatedNodeInfo]:
        """Parent node."""
        if NodeRelationship.PARENT not in self.relationships:
            return None

        relation = self.relationships[NodeRelationship.PARENT]
        if not isinstance(relation, RelatedNodeInfo):
            raise ValueError("Parent object must be a single RelatedNodeInfo object")
        return relation

    @property
    def child_nodes(self) -> Optional[List[RelatedNodeInfo]]:
        """Child nodes."""
        if NodeRelationship.CHILD not in self.relationships:
            return None

        relation = self.relationships[NodeRelationship.CHILD]
        if not isinstance(relation, list):
            raise ValueError("Child objects must be a list of RelatedNodeInfo objects.")
        return relation

    @property
    def ref_doc_id(self) -> Optional[str]:  # pragma: no cover
        """Deprecated: Get ref doc id."""
        source_node = self.source_node
        if source_node is None:
            return None
        return source_node.node_id

    @property
    @deprecated(
        version="0.12.2",
        reason="'extra_info' is deprecated, use 'metadata' instead.",
    )
    def extra_info(self) -> dict[str, Any]:  # pragma: no coverde
        return self.metadata

View on GitHub (pinned to afd0fef371)

Solutions

  1. Always store CHILD as a list, even with one element: [RelatedNodeInfo(...)]
  2. Guard JSON ingestion: if the parsed CHILD is not a list, wrap it in one
  3. Use core node parsers to generate child links

Example fix

# before
node.relationships[NodeRelationship.CHILD] = RelatedNodeInfo(node_id=child_id)

# after
node.relationships[NodeRelationship.CHILD] = [RelatedNodeInfo(node_id=child_id)]
Defensive patterns

Strategy: validation

Validate before calling

rel = node.relationships.get(NodeRelationship.CHILD)
if rel is not None and not isinstance(rel, list):
    node.relationships[NodeRelationship.CHILD] = [rel if isinstance(rel, RelatedNodeInfo) else RelatedNodeInfo.model_validate(rel)]

Type guard

def has_valid_children(node) -> bool:
    rel = node.relationships.get(NodeRelationship.CHILD)
    return rel is None or (isinstance(rel, list) and all(isinstance(r, RelatedNodeInfo) for r in rel))

Prevention

When it happens

Trigger: Setting relationships[NodeRelationship.CHILD] = RelatedNodeInfo(...) (single object) or a dict, then reading .child_nodes.

Common situations: Builders that treat CHILD like PREVIOUS/NEXT/PARENT and store one object; JSON round-trips that collapse a one-element list into a bare object.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/946cc21a20e91cb9. Report an issue: GitHub.