bytedance/deer-flow · error · ValueError

unsupported FTS5 retrieval mode: {mode}

Error message

unsupported FTS5 retrieval mode: {mode}

What it means

ValueError from FTS5RetrievalAdapter.search: the mode parameter is not one of the supported retrieval modes {'hybrid', 'fts5', 'lexical'}. Empty query or top_k<=0 return [] harmlessly, but an unknown mode is a programming/config error and rejected.

Source

Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/retrieval.py:621

            encoded_scopes = [_scope_key(scope) for scope in scopes]
        self._engine.replace_documents(documents, scopes=encoded_scopes)

    def remove(self, fact_id: str, *, scope: dict[str, str | None]) -> None:
        self._engine.remove_fact(self._document_id(fact_id, scope))

    def search(
        self,
        query: str,
        *,
        scopes: list[dict[str, str | None]],
        top_k: int,
        mode: str,
        filters: dict[str, Any] | None,
    ) -> list[dict[str, Any]]:
        if not query.strip() or top_k <= 0:
            return []
        if mode not in {"hybrid", "fts5", "lexical"}:
            raise ValueError(f"unsupported FTS5 retrieval mode: {mode}")

        filters = filters or {}
        category = filters.get("category")
        if category is not None and not isinstance(category, str):
            raise ValueError("retrieval category filter must be a string")

        results: list[dict[str, Any]] = []
        per_scope_limit = top_k * 4
        for scope in scopes:
            scope_user, scope_agent = _scope_key(scope)
            for candidate in self._engine.search(
                query,
                scope_user=scope_user,
                scope_agent=scope_agent,
                category=category,
                top_k=per_scope_limit,
            ):
                fact = dict(candidate)

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Use one of: 'hybrid', 'fts5', or 'lexical' when calling the FTS5 adapter.
  2. Validate mode against the adapter's supported set before calling (or expose it via the adapter) when it comes from config.
  3. If you need semantic/vector retrieval, configure a retrieval backend that supports it rather than passing its mode name here.
  4. Normalize case/whitespace on mode strings from user input.

Example fix

# before
results = adapter.search(q, scopes=scopes, top_k=8, mode="semantic")

# after
results = adapter.search(q, scopes=scopes, top_k=8, mode="hybrid")
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED = {'hybrid', 'fts5', 'lexical'}
mode = (mode or 'hybrid').strip().lower()
if mode not in SUPPORTED:
    raise ConfigError(f'retrieval mode {mode!r} unsupported; choose from {sorted(SUPPORTED)}')

Type guard

def is_supported_mode(mode) -> bool:
    return isinstance(mode, str) and mode in {'hybrid', 'fts5', 'lexical'}

Try / catch

try:
    results = adapter.search(q, scopes=scopes, top_k=k, mode=mode)
except ValueError as e:
    if 'unsupported FTS5 retrieval mode' in str(e):
        results = adapter.search(q, scopes=scopes, top_k=k, mode='hybrid')  # known-good default
    else:
        raise

Prevention

When it happens

Trigger: Calling search(..., mode='semantic') or mode='vector' (not supported by the FTS5 adapter), or forwarding a user/config-supplied mode string unvalidated.

Common situations: Config file sets retrieval mode to a vector/semantic name on a deployment using the FTS5-only adapter; mode string typo ('Fts5', 'hybrid ' with space); newer caller sending a mode added to a different retrieval backend.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/8c4fa0b87c8a2205. Report an issue: GitHub.