run-llama/llama_index · error · ValueError

ref_doc_id of node cannot be None when building a document s

Error message

ref_doc_id of node cannot be None when building a document summary index

What it means

A DocumentSummaryIndex groups nodes under per-document summary nodes, keyed by the summary node's ref_doc_id (the id of the source Document). add_summary_and_nodes() rejects a summary node with ref_doc_id=None because there would be no document key to register the summary under, silently breaking retrieval.

Source

Thrown at llama-index-core/llama_index/core/data_structs/document_summary.py:35

    """

    summary_id_to_node_ids: Dict[str, List[str]] = field(default_factory=dict)
    node_id_to_summary_id: Dict[str, str] = field(default_factory=dict)

    # track mapping from doc id to node summary id
    doc_id_to_summary_id: Dict[str, str] = field(default_factory=dict)

    def add_summary_and_nodes(
        self,
        summary_node: BaseNode,
        nodes: List[BaseNode],
    ) -> str:
        """Add node and summary."""
        summary_id = summary_node.node_id
        ref_doc_id = summary_node.ref_doc_id
        if ref_doc_id is None:
            raise ValueError(
                "ref_doc_id of node cannot be None when building a document "
                "summary index"
            )
        self.doc_id_to_summary_id[ref_doc_id] = summary_id

        for node in nodes:
            node_id = node.node_id
            if summary_id not in self.summary_id_to_node_ids:
                self.summary_id_to_node_ids[summary_id] = []
            self.summary_id_to_node_ids[summary_id].append(node_id)

            self.node_id_to_summary_id[node_id] = summary_id

        return summary_id

    @property
    def summary_ids(self) -> List[str]:
        """Get summary ids."""

View on GitHub (pinned to afd0fef371)

Solutions

  1. Feed Documents to the index and let it split: DocumentSummaryIndex.from_documents(docs) — splitter sets ref_doc_id on every node
  2. If you must pass nodes, set node.ref_doc_id = doc_id on each (especially the summary) node before building
  3. Check for None first and route offending nodes through a Document wrapper: insert them into Document(text=..., id_=known_id) then split

Example fix

// before
nodes = [TextNode(text="some content")]  # ref_doc_id is None
index = DocumentSummaryIndex(nodes=nodes)  # ValueError

// after
from llama_index.core import Document
from llama_index.core.node_parser import SentenceSplitter
nodes = SentenceSplitter().get_nodes_from_documents(
    [Document(text="some content", id_="doc_1")]
)  # ref_doc_id set automatically
index = DocumentSummaryIndex(nodes=nodes)
Defensive patterns

Strategy: validation

Validate before calling

missing = [n.id_ for n in nodes if n.ref_doc_id is None]
if missing:
    raise ValueError(f"nodes without ref_doc_id: {missing}")

Type guard

def nodes_have_ref_doc_id(nodes) -> bool:
    return all(n.ref_doc_id is not None for n in nodes)

Prevention

When it happens

Trigger: Building a DocumentSummaryIndex from nodes you created manually (TextNode(...) has no ref_doc_id) instead of nodes produced by a splitter from Documents; or passing summary nodes whose ref_doc_id was stripped (e.g. after node transformations or copying nodes).

Common situations: Reusing an existing node list (from another index or an ingestion cache) as input to DocumentSummaryIndex; inserting manually-written summary TextNodes; transformations that clear ref_doc_id.

Related errors


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