run-llama/llama_index · error · ValueError

Index was constructed without building trees, but retriever

Error message

Index was constructed without building trees, but retriever mode {retriever_mode} requires trees.

What it means

TreeIndex._validate_build_tree_required raises ValueError when the requested retriever mode is in REQUIRE_TREE_MODES ({SELECT_LEAF, SELECT_LEAF_EMBEDDING, ROOT}) but the index was constructed with build_tree=False. build_tree=False stores only leaf nodes with no LLM-generated summary hierarchy, so any mode that must traverse or select among internal tree summaries cannot work. Only ALL_LEAF mode (brute-force embedding search over leaves) is valid on a treeless index.

Source

Thrown at llama-index-core/llama_index/core/indices/tree/base.py:133

        if retriever_mode == TreeRetrieverMode.SELECT_LEAF:
            return TreeSelectLeafRetriever(self, object_map=self._object_map, **kwargs)
        elif retriever_mode == TreeRetrieverMode.SELECT_LEAF_EMBEDDING:
            embed_model = embed_model or Settings.embed_model
            return TreeSelectLeafEmbeddingRetriever(
                self, embed_model=embed_model, object_map=self._object_map, **kwargs
            )
        elif retriever_mode == TreeRetrieverMode.ROOT:
            return TreeRootRetriever(self, object_map=self._object_map, **kwargs)
        elif retriever_mode == TreeRetrieverMode.ALL_LEAF:
            return TreeAllLeafRetriever(self, object_map=self._object_map, **kwargs)
        else:
            raise ValueError(f"Unknown retriever mode: {retriever_mode}")

    def _validate_build_tree_required(self, retriever_mode: TreeRetrieverMode) -> None:
        """Check if index supports modes that require trees."""
        if retriever_mode in REQUIRE_TREE_MODES and not self.build_tree:
            raise ValueError(
                "Index was constructed without building trees, "
                f"but retriever mode {retriever_mode} requires trees."
            )

    def _build_index_from_nodes(
        self, nodes: Sequence[BaseNode], **build_kwargs: Any
    ) -> IndexGraph:
        """Build the index from nodes."""
        index_builder = GPTTreeIndexBuilder(
            self.num_children,
            self.summary_template,
            llm=self._llm,
            use_async=self._use_async,
            show_progress=self._show_progress,
            docstore=self._docstore,
        )
        return index_builder.build_from_nodes(nodes, build_tree=self.build_tree)

View on GitHub (pinned to afd0fef371)

Solutions

  1. If you need leaf-selection retrieval, rebuild the index with build_tree=True: TreeIndex(nodes, build_tree=True).
  2. If you want to keep the cheap treeless index, retrieve with retriever_mode=TreeRetrieverMode.ALL_LEAF (embedding search over leaves).
  3. Decide the retrieval strategy before ingestion — the trade-off (LLM cost now vs. traversal later) is fixed at build time.

Example fix

# before
index = TreeIndex(nodes, build_tree=False)
retriever = index.as_retriever()  # default SELECT_LEAF -> ValueError

# after (option A: build the tree)
index = TreeIndex(nodes, build_tree=True)
retriever = index.as_retriever()
# after (option B: stay treeless)
retriever = index.as_retriever(retriever_mode=TreeRetrieverMode.ALL_LEAF)
Defensive patterns

Strategy: validation

Validate before calling

from llama_index.core.indices.tree.base import REQUIRE_TREE_MODES, TreeRetrieverMode

def can_use_mode(index, mode: TreeRetrieverMode) -> bool:
    return index.build_tree or mode not in REQUIRE_TREE_MODES

# usage: assert can_use_mode(index, TreeRetrieverMode.SELECT_LEAF)

Type guard

from llama_index.core.indices.tree.base import REQUIRE_TREE_MODES

def mode_requires_tree(mode) -> bool:
    return mode in REQUIRE_TREE_MODES

Try / catch

try:
    retriever = index.as_retriever(retriever_mode=mode)
except ValueError:
    retriever = index.as_retriever(retriever_mode=TreeRetrieverMode.ALL_LEAF)  # treeless fallback

Prevention

When it happens

Trigger: TreeIndex(nodes, build_tree=True, use_async=True) omitted / set False (e.g. building from existing Documents with build_tree=False for cheap ingestion), then calling as_retriever(retriever_mode=TreeRetrieverMode.SELECT_LEAF).

Common situations: Choosing build_tree=False to skip LLM summarization cost at ingest, then expecting default select_leaf retrieval to still work; loading an index persisted by a pipeline that built it treeless; parameter renamed/added across versions so old scripts silently default to False.

Related errors


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