bytedance/deer-flow · info · HTTPException
Feedback {feedback_id} not found
Error message
Feedback {feedback_id} not found What it means
Raised by DELETE /threads/{thread_id}/runs/{run_id}/feedback/{feedback_id} with status 404 when feedback_repo.get(feedback_id) returns None — the feedback record with that id does not exist. This is the pre-delete existence check; deletion never proceeds on a missing record.
Source
Thrown at backend/app/gateway/routers/feedback.py:183
"""Get aggregated feedback stats (positive/negative counts) for a run."""
feedback_repo = get_feedback_repo(request)
return await feedback_repo.aggregate_by_run(thread_id, run_id)
@router.delete("/{thread_id}/runs/{run_id}/feedback/{feedback_id}")
@require_permission("threads", "delete", owner_check=True, require_existing=True)
async def delete_feedback(
thread_id: ThreadId,
run_id: str,
feedback_id: str,
request: Request,
) -> dict[str, bool]:
"""Delete a feedback record."""
feedback_repo = get_feedback_repo(request)
# Verify feedback belongs to the specified thread/run before deleting
existing = await feedback_repo.get(feedback_id)
if existing is None:
raise HTTPException(status_code=404, detail=f"Feedback {feedback_id} not found")
if existing.get("thread_id") != thread_id or existing.get("run_id") != run_id:
raise HTTPException(status_code=404, detail=f"Feedback {feedback_id} not found in run {run_id}")
deleted = await feedback_repo.delete(feedback_id)
if not deleted:
raise HTTPException(status_code=404, detail=f"Feedback {feedback_id} not found")
return {"success": True}
View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Re-fetch the feedback list for the run and delete using a fresh feedback_id.
- Prefer the simpler by-run delete endpoint (DELETE .../runs/{run_id}/feedback) when deleting the current user's own feedback.
- Treat 404 as already-deleted in idempotent clients.
Example fix
// before
await del(`/api/threads/${tid}/runs/${rid}/feedback/${staleFeedbackId}`);
// after
const fb = (await listFeedback(tid, rid)).find(f => f.id === staleFeedbackId);
if (fb) await del(`/api/threads/${tid}/runs/${rid}/feedback/${fb.id}`); Defensive patterns
Strategy: validation
Validate before calling
const list = await listFeedback(threadId, runId);
const fb = list.find(f => f.id === feedbackId);
if (fb) await del(`/api/threads/${threadId}/runs/${runId}/feedback/${fb.id}`); Try / catch
try { await del(url); } catch (e) { if (e.status === 404) return; throw e; } Prevention
- Delete using a fresh feedback_id from a just-fetched list
- Prefer the by-run delete for the user's own feedback
- Treat 404 as already-deleted
When it happens
Trigger: Deleting with a malformed or fabricated feedback_id; deleting feedback already removed via the by-run delete endpoint or by another admin/session; the feedback table/store was reset between listing and deleting.
Common situations: Two UI panels offering delete (by-run and by-id) racing each other; stale feedback list in the UI after a concurrent delete; store migrations wiping feedback rows.
Related errors
- No feedback found for this run
- Feedback {feedback_id} not found in run {run_id}
- Memory fact '{fact_id}' not found.
- File not found: {filename}
- Failed to delete local thread data.
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/17cf8a3095acca7d.
Report an issue: GitHub.