JuliusBrussee/caveman · error · ValueError
Agno middleware requires a nonempty native session_id
Error message
Agno middleware requires a nonempty native session_id
What it means
scope_from_run derives a Caveman Scope from a native Agno Agent/Team run, and the session_id is the mandatory scope key for branching and recovery. If the run object has no session_id, or it is empty/non-string, scoping is impossible so it raises ValueError.
Solutions
- Ensure the Agent/Team run has a nonempty session_id: pass session_id="<id>" when creating/running it
- Generate a session id if your workflow has none (e.g. uuid4().hex) before invoking the adapter
- Check you are passing the run object that actually carries session_id
- Loosen the check only if you can supply an alternative scope key via a custom scope resolver returning a Scope
Example fix
# before agent.run(input) # run.session_id is None -> ValueError # after agent.run(input, session_id=str(uuid4()))
Defensive patterns
Strategy: validation
Validate before calling
def ensure_run_scopable(run):
sid = getattr(run, "session_id", None)
if not isinstance(sid, str) or not sid:
raise ValueError("run must carry a nonempty session_id before adapter use")
return sid Type guard
def has_session(run) -> bool:
sid = getattr(run, "session_id", None)
return isinstance(sid, str) and bool(sid) Try / catch
try:
scope = scope_from_run(run, namespace="my-ns")
except ValueError as e:
if "session_id" in str(e):
run.session_id = str(uuid4()) # or recreate the run with one
scope = scope_from_run(run, namespace="my-ns")
else:
raise Prevention
- Always create Agno Agent/Team runs with an explicit session_id
- Assign uuid4-based session ids in ephemeral workflows
- Validate run fixtures in tests carry session_id
- After agno upgrades, re-check that session_id is populated at run construction
When it happens
Trigger: Calling scope_from_run (or the adapter's state/_frame path that uses it) with a run object created without session_id, with session_id="", or with a mock/stub lacking the attribute.
Common situations: Running an Agno agent in ephemeral/no-session mode; constructing runs manually in tests without session_id; upgrading agno where session assignment became lazy; passing the wrong object (e.g. a Run result instead of the run config).
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Agno scope resolver must return a Caveman Scope
- AutoGen requires a stable Caveman Scope for each agent or…
- Expected an existing native Agno Model
- Install caveman-middleware[agno] to use the Agno adapter
- invalid_scope
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/d941f52f68373e83.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/agno.py:37
from agno.tools.function import Function
except ModuleNotFoundError as error:
raise ImportError("Install caveman-middleware[agno] to use the Agno adapter") from error
from caveman_cloud.middleware import Adapter, Candidate, MiddlewareError, MiddlewareRuntime, Scope
from caveman_cloud.middleware.runtime import RECOVERY_DESCRIPTION, RECOVERY_SCHEMA
from ._native import Attempt, manifest, owner, plain
from ._versions import matches_framework
ADAPTER = Adapter("agno", "0.1.0", "3.0.9", "agno-message-v1")
_SIGNATURES = {name: inspect.signature(getattr(Model, name)) for name in
("response", "aresponse", "response_stream", "aresponse_stream")}
def scope_from_run(run, *, namespace: str) -> Scope:
"""Resolve a native Agent or Team run's session, with explicit branch metadata."""
session = getattr(run, "session_id", None)
if not isinstance(session, str) or not session:
raise ValueError("Agno middleware requires a nonempty native session_id")
metadata = getattr(run, "metadata", None) or {}
return Scope(namespace, session, metadata.get("caveman_branch_id", "main"), metadata.get("caveman_cache_epoch", "0"))
def _scope(source, run):
result = source if isinstance(source, Scope) else source(run)
if not isinstance(result, Scope):
raise TypeError("Agno scope resolver must return a Caveman Scope")
return result
def _message_view(messages):
if type(messages) is not list or any(type(message) is not Message for message in messages):
return None
# Metrics/timers and checkpoint bookkeeping are not model input. All other
# native values participate in lineage; opaque values bypass the whole view.
excluded = {"metrics", "created_at", "from_history", "checkpoint_status", "checkpoint_created_at"}
try:View on GitHub (pinned to 3ee70a1026)