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
DocumentSummaryIndex groups nodes by their ref_doc_id (the source document id) to build per-document summaries. During _add_nodes_to_index, any node whose ref_doc_id is None cannot be attributed to a document, so the build fails immediately with ValueError. Nodes parsed through the standard node-parser pipeline always carry ref_doc_id; hand-constructed nodes often don't.
Source
Thrown at llama-index-core/llama_index/core/indices/document_summary/base.py:175
doc_id (str): A document id.
"""
if doc_id not in self._index_struct.doc_id_to_summary_id:
raise ValueError(f"doc_id {doc_id} not in index")
summary_id = self._index_struct.doc_id_to_summary_id[doc_id]
return self.docstore.get_node(summary_id).get_content()
def _add_nodes_to_index(
self,
index_struct: IndexDocumentSummary,
nodes: Sequence[BaseNode],
show_progress: bool = False,
) -> None:
"""Add nodes to index."""
doc_id_to_nodes = defaultdict(list)
for node in nodes:
if node.ref_doc_id is None:
raise ValueError(
"ref_doc_id of node cannot be None when building a document "
"summary index"
)
doc_id_to_nodes[node.ref_doc_id].append(node)
summary_node_dict = {}
items = doc_id_to_nodes.items()
iterable_with_progress = get_tqdm_iterable(
items, show_progress, "Summarizing documents"
)
for doc_id, nodes in iterable_with_progress:
print(f"current doc id: {doc_id}")
nodes_with_scores = [NodeWithScore(node=n) for n in nodes]
# get the summary for each doc_id
summary_response = self._response_synthesizer.synthesize(
query=self._summary_query,
nodes=nodes_with_scores,View on GitHub (pinned to afd0fef371)
Solutions
- Build nodes through a node parser: SentenceSplitter().get_nodes_from_documents(docs) — these set ref_doc_id automatically.
- If constructing nodes manually, set the source relationship: node.relationships[NodeRelationship.SOURCE] = RelatedNodeInfo(source_id=doc_id) or pass source_node to TextNode.
- Filter/reject nodes with ref_doc_id None before insert: nodes = [n for n in nodes if n.ref_doc_id is not None].
Example fix
# before
nodes = [TextNode(text=t) for t in chunks] # no ref_doc_id -> ValueError
index = DocumentSummaryIndex(nodes=nodes)
# after
from llama_index.core.schema import TextNode, RelatedNodeInfo, NodeRelationship
nodes = [
TextNode(
text=t,
relationships={NodeRelationship.SOURCE: RelatedNodeInfo(source_id=f"doc-{i}")},
)
for i, t in enumerate(chunks)
]
index = DocumentSummaryIndex(nodes=nodes) Defensive patterns
Strategy: validation
Validate before calling
orphaned = [n.id_ for n in nodes if n.ref_doc_id is None]
if orphaned:
raise ValueError(f"Nodes missing SOURCE relationship: {orphaned}") Type guard
def all_nodes_have_source(nodes) -> bool:
return all(n.ref_doc_id is not None for n in nodes) Prevention
- Generate nodes with node parsers so ref_doc_id is set automatically.
- When building nodes manually, always set relationships[NodeRelationship.SOURCE].
When it happens
Trigger: Building DocumentSummaryIndex.from_documents with a custom transformation that returns TextNode objects built directly (no relationships); inserting nodes via index.insert_nodes where nodes lack a SOURCE relationship; loading nodes from external storage without restoring relationships.
Common situations: Custom node pipelines that create TextNode(text=...) manually; caching layers that serialize nodes to dicts and lose the Source relationship; converting other frameworks' chunks into llama-index nodes.
Related errors
- ref_doc_id of node cannot be None when building a document s
- Cannot use embedding retriever if embed_summaries is False
- Unknown retriever mode: {retriever_mode}
- doc_id {doc_id} not in index
- Max iterations of {max_iterations} reached! Either something
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/76eb806840fe51b4.
Report an issue: GitHub.