{"record":{"id":"d72d373eb1331669","repo":"bytedance/deer-flow","slug":"message-message-id-not-found","errorCode":null,"errorMessage":"Message {message_id} not found","messagePattern":"Message (.+?) not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"backend/app/gateway/routers/thread_runs.py","lineNumber":654,"sourceCode":"        logger.exception(\"Failed to read latest checkpoint for regenerate thread %s\", thread_id)\n        raise HTTPException(status_code=500, detail=\"Failed to read latest checkpoint\") from exc\n    latest_checkpoint_id = _checkpoint_configurable(latest_checkpoint).get(\"checkpoint_id\")\n    if not latest_checkpoint_id:\n        raise HTTPException(status_code=404, detail=f\"Thread {thread_id} has no checkpoint\")\n\n    messages = _checkpoint_messages(latest_checkpoint)\n    target_index = next((i for i, message in enumerate(messages) if _message_id(message) == message_id), None)\n    if target_index is None:\n        # A response interrupted during an LLM call can be visible in the live\n        # stream without ever reaching a checkpoint. The server-stamped run ID\n        # on the latest user message is the durable link to that partial turn.\n        previous_human = next(\n            (message for message in reversed(messages) if _is_visible_human_message(message)),\n            None,\n        )\n        target_run_id = await _find_interrupted_target_run_id(thread_id, previous_human, request) if previous_human is not None else None\n        if target_run_id is None:\n            raise HTTPException(status_code=404, detail=f\"Message {message_id} not found\")\n    else:\n        target_message = messages[target_index]\n        if not _is_visible_ai_message(target_message):\n            raise HTTPException(status_code=409, detail=\"Only visible assistant messages can be regenerated\")\n\n        latest_visible_ai = next((message for message in reversed(messages) if _is_visible_ai_message(message)), None)\n        if _message_id(latest_visible_ai) != message_id:\n            raise HTTPException(status_code=409, detail=\"Only the latest assistant message can be regenerated\")\n\n        previous_human = next((message for message in reversed(messages[:target_index]) if _is_visible_human_message(message)), None)\n        target_run_id = (\n            await _find_target_run_id(\n                thread_id,\n                message_id,\n                target_message,\n                previous_human,\n                request,\n            )","sourceCodeStart":636,"sourceCodeEnd":672,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/thread_runs.py#L636-L672","documentation":"Raised in _prepare_regenerate_payload (HTTP 404) when message_id matches no message in the latest checkpoint AND the interrupted-run fallback (server-stamped run_id on the latest user message, only when that run has status 'interrupted') yields nothing. The message the client wants to regenerate is unknown to the checkpointed state.","triggerScenarios":"Regenerating a streaming-only message that never checkpointed while its run is not in interrupted status (e.g. still running or already succeeded elsewhere); passing a client-side message id; message from a different thread.","commonSituations":"Regenerate clicked while the target response is mid-stream; stale UI state after the thread advanced; id confusion between UI-rendered messages and checkpointed ones.","solutions":["Refetch thread state and regenerate a message id that appears in the checkpointed messages list.","Wait until the current run finishes (or is clearly interrupted) before regenerating its output.","Ensure the frontend uses server-assigned message ids for regenerate targets."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const st = await getThreadState(threadId);\nconst exists = st.messages.some(m => m.id === messageId);\nif (!exists && !isRunInterrupted(st.latest_run)) { await refreshThread(threadId); return; }","typeGuard":"function messageExistsInState(messages: {id?: string}[], id: string): boolean {\n  return messages.some(m => m.id === id);\n}","tryCatchPattern":"try { await regeneratePrepare(threadId, messageId); } catch (e) { if (e.status === 404 && /not found/.test(e.detail)) { await refreshThread(threadId); } else throw e; }","preventionTips":["Disable regenerate while the run is streaming","Use server message ids","Refresh transcript before rewind actions"],"tags":["regenerate","message-id","http-404"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}