bytedance/deer-flow · error · ValueError
Invalid OpenViking peer scope: {agent_name!r}
Error message
Invalid OpenViking peer scope: {agent_name!r} What it means
_canonical_peer_id() in session.py raises ValueError when the supplied agent_name, after strip().lower(), is empty or equals the reserved default scope '__default__'. Agent names are mapped to disjoint OpenViking actor peer IDs; the default scope is reserved for the manager-level default (agent_name=None) and cannot be passed explicitly, and an empty name has no peer identity.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/openviking/session.py:28
from .config import GENERATED_PEER_PREFIX, is_safe_peer_id
_SESSION_NAMESPACE = "deerflow-openviking-adapter-v1"
_DEFAULT_AGENT_SCOPE = "__default__"
_CURSOR_SCHEMA_VERSION = 1
def _canonical_peer_id(
agent_name: str | None,
default_peer_id: str,
) -> str:
"""Map DeerFlow's case-insensitive agent names to disjoint peer IDs."""
if agent_name is None:
return default_peer_id
value = str(agent_name).strip().lower()
if not value or value == _DEFAULT_AGENT_SCOPE:
raise ValueError(f"Invalid OpenViking peer scope: {agent_name!r}")
if is_safe_peer_id(value) and value != default_peer_id and not value.startswith(GENERATED_PEER_PREFIX):
return value
# The generated namespace is reserved, so compatible names, the default
# peer, and hashed fallbacks cannot alias one another. The 128-bit digest
# also avoids collisions caused by sanitizing or truncating agent names.
digest = hashlib.sha256(value.encode("utf-8")).hexdigest()[:32]
return f"{GENERATED_PEER_PREFIX}{digest}"
def _session_id(
owner_user_id: str,
peer_id: str,
thread_id: str,
) -> str:
"""Derive one stable OpenViking session for one DeerFlow thread."""
digest = hashlib.sha256(f"{_SESSION_NAMESPACE}\0{owner_user_id}\0{peer_id}\0{thread_id}".encode()).hexdigest()View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Pass agent_name=None when you mean the default peer — the manager substitutes config default_peer_id
- Use a real non-empty agent name; any unsafe characters are automatically hashed, so no sanitization is needed
- Never forward DeerMem's '__default__' sentinel to OpenViking-backed operations
Example fix
# before manager.add(thread_id, msgs, agent_name='__default__', user_id='default') # after manager.add(thread_id, msgs, agent_name=None, user_id='default')
Defensive patterns
Strategy: validation
Validate before calling
def safe_agent_name(agent_name: str | None) -> str | None:
if agent_name is None:
return None
normalized = str(agent_name).strip().lower()
if not normalized or normalized == "__default__":
return None # or raise: explicit default scope is not a valid peer
return agent_name Type guard
def is_valid_explicit_peer(agent_name: object) -> bool:
if not isinstance(agent_name, str):
return agent_name is None
v = agent_name.strip().lower()
return bool(v) and v != "__default__" Prevention
- Pass agent_name=None for the default peer; never forward '__default__' to OpenViking-backed calls
- Validate agent names at your API boundary before they reach the memory manager
When it happens
Trigger: Calling memory operations with agent_name='' , agent_name=' ', or agent_name='__default__' (case-insensitive). Other unsafe names do not raise — they are hashed into the reserved 'df-agent-' namespace instead; only these two degenerate forms are rejected.
Common situations: Passing the DeerMem sentinel '__default__' explicitly through the OpenViking backend (only DeerMem storage accepts it); a caller building agent_name from empty config or an unset subagent name.
Related errors
- OpenViking memory write requires thread_id
- backend_unreachable
- request_failed
- Unable to recover SSE history after ${recoveryAttempts} atte
- Failed to submit feedback: ${res.status}
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/34204b67832bac1a.
Report an issue: GitHub.