iflytek/astron-agent · error · CustomException

23900

23900

Error message

Conversation has timed out or does not exist

What it means

Raised by EventRegistry.get_event when no entry exists in Redis for the given event_id key. The workflow uses this registry to park events awaiting user (interrupt) responses; a missing entry means the event expired (TTL) or was deleted. Callers like update_event, on_interrupt, on_interrupt_node_start/end surface it as 'Conversation has timed out or does not exist'.

Solutions

  1. Check event existence with get_cache_service().get(key=EventRegistry._event_key(event_id)) before resuming, and return a friendly 'conversation expired' response to the user
  2. Extend or configure the TTL used when the event is stored in the registry so long-running waits are not evicted
  3. Regenerate the conversation: have the client start a new workflow run instead of resuming a dead event_id
  4. Verify Redis persistence/eviction settings (maxmemory-policy) so events are not dropped unexpectedly

Example fix

// before
result = await agent.resume(event_id, user_input)  # raises 23900
// after
if not cache.get(key=EventRegistry._event_key(event_id)):
    return ConversationExpiredResponse(event_id=event_id)
result = await agent.resume(event_id, user_input)
Defensive patterns

Strategy: try-catch

Validate before calling

def event_exists(event_id: str) -> bool:
    return get_cache_service().get(key=EventRegistry._event_key(event_id)) is not None

Try / catch

try:
    event = EventRegistry.get_event(event_id)
except CustomException as e:
    if e.err_code == CodeEnum.EVENT_REGISTRY_NOT_FOUND_ERROR:
        return expire_conversation(event_id)
    raise

Prevention

When it happens

Trigger: Calling EventRegistry.get_event(event_id) (directly or via update_event/on_interrupt* handlers) with an event_id whose Redis key has expired via TTL or was removed by del_event; resuming a conversation after the wait window elapsed; passing a malformed/never-created event_id.

Common situations: User replies to an interrupted workflow node after the session TTL expired; stale client resuming an old conversation ID after a Redis restart or cache flush; double-submit of a resume request where the first one deleted the event.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/7e3adef90c22e9b7. Report an issue: GitHub.

Appendix: source

Thrown at core/workflow/cache/event_registry.py:152

    @classmethod
    def check_event_lock(cls, event_id: str) -> bool:
        data = get_cache_service().get(key=f"event_lock:{event_id}")
        if not data:
            return False
        return True

    @classmethod
    def get_event(cls, event_id: str) -> Event:
        """
        Get event information by event ID.

        :param cls: Class itself
        :param event_id: Event ID string
        :return: Decoded event object if found, raises exception otherwise
        """
        data = get_cache_service().get(key=cls._event_key(event_id))
        if not data:
            raise CustomException(err_code=CodeEnum.EVENT_REGISTRY_NOT_FOUND_ERROR)
        return cls._decode(data)

    @classmethod
    def del_event(cls, event_id: str) -> None:
        """
        Delete event by event ID.

        :param cls: Class itself for accessing class variables and methods
        :param event_id: ID of the event to delete
        """
        get_cache_service().delete(cls._event_key(event_id))

    @classmethod
    def get_all_event_ids(cls) -> dict:
        """
        Get all event IDs from cache.

        :return: Dictionary containing all event IDs

View on GitHub (pinned to 5e758547a8)