langchain-ai/deepagents · error · ValueError
PreCompact requires a stable tool-call identity
Error message
PreCompact requires a stable tool-call identity
What it means
Hook invocation ids must be stable across retries so events can be deduplicated. PreCompactEvent has no tool call to derive an id from, so it depends on a caller-supplied logical_event_id; when neither a tool-call id nor a logical id exists, _logical_event_identity raises ValueError because no stable identity can be formed.
Source
Thrown at libs/code/deepagents_code/hooks/server_middleware.py:1100
| PostToolUseFailureEvent
| PreCompactEvent
| StopEvent
| SubagentStartEvent
| SubagentStopEvent
),
*,
logical_event_id: str | None = None,
) -> str:
if isinstance(
event,
PreToolUseEvent | PostToolUseEvent | PostToolUseFailureEvent,
):
return event.call.id
if isinstance(event, PreCompactEvent):
if logical_event_id:
return logical_event_id
msg = "PreCompact requires a stable tool-call identity"
raise ValueError(msg)
if isinstance(event, SubagentStartEvent):
return event.agent.id
if isinstance(event, SubagentStopEvent):
return f"{event.agent.id}:{event.continuation_count}"
message_hash = hashlib.sha256(event.last_assistant_message.encode()).hexdigest()
return f"{event.continuation_count}:{message_hash}"
def _config_thread_id(config: Mapping[str, Any] | None) -> str | None:
if not isinstance(config, Mapping):
return None
configurable = config.get("configurable")
if not isinstance(configurable, Mapping):
return None
value = configurable.get("thread_id")
return value if isinstance(value, str) and value else None
View on GitHub (pinned to a1af029e6e)
Solutions
- Pass a logical_event_id when invoking pre-compact hooks — derive it from the compaction request (e.g. a uuid or thread/turn composite key).
- Use the standard compaction flow, which assigns the logical id automatically.
- If building events in tests, supply event.call.id or a logical_event_id to satisfy identity computation.
- Catch ValueError and treat it as a programming error: regenerate the event with a stable id rather than retrying.
Example fix
// before
await middleware._invoke_hook(gate, PreCompactEvent(...), config, deadline) # ValueError
// after
await middleware._invoke_hook(
gate, PreCompactEvent(...), config, deadline,
logical_event_id=f"compact:{thread_id}:{turn}",
) Defensive patterns
Strategy: validation
Validate before calling
if isinstance(event, PreCompactEvent) and not logical_event_id:
raise ValueError("pass logical_event_id for PreCompact hook invocations") Try / catch
try:
run_compact_hooks(event, ...)
except ValueError as exc:
if "stable tool-call identity" in str(exc):
rerun_with_logical_event_id() Prevention
- Always supply logical_event_id for PreCompactEvent invocations
- Use the built-in compaction flow which assigns ids automatically
- Generate ids from stable keys (thread id + turn), not random per retry
- Cover pre-compact hooks in tests with an explicit logical id
When it happens
Trigger: A PreCompactEvent reaches _invocation_id/_logical_event_identity with logical_event_id=None and no other stable key: triggering pre-compact hooks through a path that doesn't assign a logical event id (e.g. a manual or custom compaction trigger outside the standard compact flow).
Common situations: Custom compaction pipelines firing PreCompactEvent without generating a logical_event_id; replay/retry logic that drops the logical id; tests constructing PreCompactEvent directly and invoking the middleware.
Related errors
- trusted thread, turn, and tool-call identity are required
- Permission interrupted by hook
- Compact session start stopped by hook
- Session start stopped by hook
- Offload server returned an invalid operation response.
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/eef2da2664d9e632.
Report an issue: GitHub.