{"record":{"id":"7e3adef90c22e9b7","repo":"iflytek/astron-agent","slug":"23900-conversation-has-timed-out-or-does-not-exist","errorCode":"23900","errorMessage":"Conversation has timed out or does not exist","messagePattern":"Conversation has timed out or does not exist","errorType":"error_code","errorClass":"CustomException","httpStatus":null,"severity":"error","filePath":"core/workflow/cache/event_registry.py","lineNumber":152,"sourceCode":"    @classmethod\n    def check_event_lock(cls, event_id: str) -> bool:\n        data = get_cache_service().get(key=f\"event_lock:{event_id}\")\n        if not data:\n            return False\n        return True\n\n    @classmethod\n    def get_event(cls, event_id: str) -> Event:\n        \"\"\"\n        Get event information by event ID.\n\n        :param cls: Class itself\n        :param event_id: Event ID string\n        :return: Decoded event object if found, raises exception otherwise\n        \"\"\"\n        data = get_cache_service().get(key=cls._event_key(event_id))\n        if not data:\n            raise CustomException(err_code=CodeEnum.EVENT_REGISTRY_NOT_FOUND_ERROR)\n        return cls._decode(data)\n\n    @classmethod\n    def del_event(cls, event_id: str) -> None:\n        \"\"\"\n        Delete event by event ID.\n\n        :param cls: Class itself for accessing class variables and methods\n        :param event_id: ID of the event to delete\n        \"\"\"\n        get_cache_service().delete(cls._event_key(event_id))\n\n    @classmethod\n    def get_all_event_ids(cls) -> dict:\n        \"\"\"\n        Get all event IDs from cache.\n\n        :return: Dictionary containing all event IDs","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/workflow/cache/event_registry.py#L134-L170","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Extend or configure the TTL used when the event is stored in the registry so long-running waits are not evicted","Regenerate the conversation: have the client start a new workflow run instead of resuming a dead event_id","Verify Redis persistence/eviction settings (maxmemory-policy) so events are not dropped unexpectedly"],"exampleFix":"// before\nresult = await agent.resume(event_id, user_input)  # raises 23900\n// after\nif not cache.get(key=EventRegistry._event_key(event_id)):\n    return ConversationExpiredResponse(event_id=event_id)\nresult = await agent.resume(event_id, user_input)","handlingStrategy":"try-catch","validationCode":"def event_exists(event_id: str) -> bool:\n    return get_cache_service().get(key=EventRegistry._event_key(event_id)) is not None","typeGuard":null,"tryCatchPattern":"try:\n    event = EventRegistry.get_event(event_id)\nexcept CustomException as e:\n    if e.err_code == CodeEnum.EVENT_REGISTRY_NOT_FOUND_ERROR:\n        return expire_conversation(event_id)\n    raise","preventionTips":["Check key existence before resuming an interrupted conversation","Set realistic TTLs for parked events","Handle Redis restarts/flushes as conversation loss and prompt users to restart","Deduplicate resume submissions so del_event is not raced"],"tags":["redis","cache","workflow","expired-state"],"backgroundTag":"resource-not-found","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}