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
- Use one of: 'hybrid', 'fts5', or 'lexical' when calling the FTS5 adapter.
- Validate mode against the adapter's supported set before calling (or expose it via the adapter) when it comes from config.
- If you need semantic/vector retrieval, configure a retrieval backend that supports it rather than passing its mode name here.
- 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
- Validate config-supplied retrieval modes at config load, not at query time.
- Normalize mode strings (strip/lower) before use.
- Keep the supported-mode set in one constant shared by config validation and the adapter.
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
- retrieval fact.id must be a non-empty string
- retrieval fact.content must be a non-empty string
- Missing or empty 'messages' key in {path}
- retrieval scope userId must be a string or null
- retrieval scope agentName must be a string or null
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/8c4fa0b87c8a2205.
Report an issue: GitHub.