langchain-ai/deepagents · error · ValueError
retention_revisions must be nonnegative
Error message
retention_revisions must be nonnegative
What it means
TranscriptStore keeps a configurable number of historical transcript revisions; a negative retention_revisions is nonsensical (it would mean deleting more revisions than exist / infinite pruning). __init__ validates up front and raises ValueError.
Source
Thrown at libs/code/deepagents_code/hooks/transcript.py:173
def __init__(
self,
root: Path,
*,
retention_revisions: int = DEFAULT_RETENTION_REVISIONS,
) -> None:
"""Create a store rooted at `root`.
Args:
root: Directory that will contain per-thread transcript files.
retention_revisions: Maximum prior `.bak-*` revisions retained per
transcript after each rewrite.
Raises:
ValueError: If `retention_revisions` is negative.
"""
if retention_revisions < 0:
msg = "retention_revisions must be nonnegative"
raise ValueError(msg)
self.root = root.expanduser().resolve()
self.retention_revisions = retention_revisions
self._buffers: dict[tuple[str, str | None], _TranscriptBuffer] = {}
self._lock = threading.RLock()
_ensure_private_directories(self.root, self.root)
def thread_path(self, thread_id: str) -> Path:
"""Return the materialized path for a thread transcript.
Args:
thread_id: Conversation thread identifier.
Returns:
Absolute JSONL path for the thread.
"""
return self.root / f"{_safe_component(thread_id)}.jsonl"
def agent_path(self, thread_id: str, agent_id: str) -> Path:View on GitHub (pinned to a1af029e6e)
Solutions
- Pass retention_revisions >= 0 (0 typically meaning keep no extra historical revisions; check docs for the keep-current semantics).
- If "unlimited" was intended, use the store's option for disabling retention instead of a negative number.
- Clamp or validate config at load time before constructing the store.
Example fix
// before
store = TranscriptStore(root, retention_revisions=-1) # ValueError
// after
revisions = max(0, config.get("retention_revisions", 3))
store = TranscriptStore(root, retention_revisions=revisions) Defensive patterns
Strategy: validation
Validate before calling
revisions = config.get("retention_revisions", 3)
if not isinstance(revisions, int) or revisions < 0:
raise ValueError("retention_revisions must be a nonnegative int") Prevention
- Validate retention settings at config load time
- Use max(0, value) clamping for derived values
- Treat negative values as config typos, not "unlimited"
- Document that 0 is the minimum accepted value
When it happens
Trigger: Constructing the transcript store (TranscriptStore(root, retention_revisions=...)) with a negative integer, typically from a parsed config value like retention_revisions=-1 or a subtracting expression that underflowed.
Common situations: Config file with retention_revisions: -1 intended as "unlimited"; computing retention as some_count - kept where kept > count; copying an example default incorrectly.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- ServerSelection.server_name must not be empty
- max_retries must be >= 0
- Namespace tuple must not be empty.
- Namespace component at index {i} must not be empty.
- RubricMiddleware: `max_iterations` must be positive, got {ma
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/9a140569aa39b305.
Report an issue: GitHub.