{"record":{"id":"c4e2482d9679fb8d","repo":"bytedance/deer-flow","slug":"edited-message-cannot-be-empty","errorCode":null,"errorMessage":"Edited message cannot be empty","messagePattern":"Edited message cannot be empty","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"info","filePath":"backend/app/gateway/routers/thread_runs.py","lineNumber":721,"sourceCode":"        # the older automatically generated title (#4457).\n        regenerate_input[\"title\"] = latest_title\n    return RegeneratePrepareResponse(\n        input=regenerate_input,\n        checkpoint=checkpoint,\n        metadata=metadata,\n        target_run_id=target_run_id,\n    )\n\n\nasync def _prepare_edit_regenerate_payload(\n    thread_id: str,\n    human_message_id: str,\n    replacement_text: str,\n    request: Request,\n) -> EditRegeneratePrepareResponse:\n    normalized_text = replacement_text.strip()\n    if not normalized_text:\n        raise HTTPException(status_code=409, detail=\"Edited message cannot be empty\")\n\n    accessor, latest_config = await build_thread_checkpoint_state_accessor(request, thread_id=thread_id)\n    try:\n        latest_checkpoint = await accessor.aget(latest_config)\n    except Exception as exc:\n        logger.exception(\"Failed to read latest checkpoint for edit replay 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    if _has_active_goal(latest_checkpoint):\n        raise HTTPException(status_code=409, detail=\"Cannot edit while a goal is active\")\n\n    _, source_human, _, source_ai, source_message_ids = _latest_editable_turn(messages, human_message_id)\n    source_text = get_original_user_content_text(_message_content(source_human), _message_additional_kwargs(source_human)).strip()\n    if normalized_text == source_text:","sourceCodeStart":703,"sourceCodeEnd":739,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/thread_runs.py#L703-L739","documentation":"Raised in _prepare_edit_regenerate_payload (HTTP 409) when the replacement text for an edited user message strips to an empty string. An edit that produces no user content cannot be replayed, so it is rejected up front before any checkpoint access.","triggerScenarios":"POST to the edit-prepare endpoint with a body whose replacement/new_message field is '', whitespace-only, or missing.","commonSituations":"Frontend sends the form before the user types; whitespace-only paste; JSON field name mismatch (e.g. 'text' vs 'new_message') silently defaulting to empty.","solutions":["Client-side validate the edit box is non-empty (after trim) before enabling submit.","Check the request field name matches the endpoint's schema exactly.","Send the trimmed text explicitly in the request body."],"exampleFix":"// before\nawait editPrepare(threadId, humanId, draftText);\n// after\nconst text = draftText.trim();\nif (!text) return;\nawait editPrepare(threadId, humanId, text);","handlingStrategy":"validation","validationCode":"const text = (draft ?? '').trim();\nif (!text) { keepEditorOpen(); return; } // do not call the endpoint","typeGuard":"function isValidEditText(text: unknown): text is string {\n  return typeof text === 'string' && text.trim().length > 0;\n}","tryCatchPattern":"try { await editPrepare(threadId, humanId, text); } catch (e) { if (e.status === 409 && /cannot be empty/.test(e.detail)) { showFieldError('Message cannot be empty'); } else throw e; }","preventionTips":["Trim and require non-empty before submit","Disable submit button for empty drafts","Match the endpoint's field name exactly"],"tags":["edit","validation","http-409"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}