review agent failed to thread its replies: replies went to the wrong conversation: how to fix
Fix for review agents that reply to the wrong review thread because they matched by line number instead of thread identity. Use when bot replies land under unrelated comments, follow-ups attach to the wrong conversation, or reviewers see answers in threads they never asked in. Key triggers: line-based reply matching, replies in wrong threads. Not for agents that open duplicate threads instead of replying.
TL;DR
Reply by thread ID, never by file and line. Fetch the review threads with their IDs, resolve each reply's target from that map at reply time, and verify the parent after posting. Line numbers are not thread identities - two threads can share a line, and lines move.
The problem
review agent failed to thread its replies: replies went to the wrong conversation: how to fixWhen to use
- Bot replies land under the wrong comments
- Follow-ups attach to unrelated conversations
- Reviewers see answers in threads they never participated in
- The agent "replied" but nobody can find the reply in the right place
When not to use
- The agent opened a new thread instead of replying (a thread-matching bug, the reverse problem)
- Replies are correct but duplicated (an idempotency issue)
- The target thread was deleted (then any reply target is wrong; handle explicitly)
Steps
1. Fetch review threads with their IDs
Use GraphQL reviewThreads for thread node IDs, or the REST review-comments endpoint for comment IDs you can reply under. Keep the id, path, line, and resolved state together.
Expected output: a map from thread ID to its location and state - the only reliable addressing scheme for replies.
2. Key every reply by thread ID, never by file and line
When the agent decides to respond to a conversation, it must name the thread ID from the step-1 map. Matching "the thread on line 42 of app.py" is how mixups happen: lines shift and multiple threads share lines.
Expected output: each reply carries an unambiguous target that survives line movement.
3. Resolve the target thread at reply time from a fresh map
Do not cache thread IDs across long runs. Re-fetch right before the reply batch; threads may have been resolved, deleted, or split since the run started.
Expected output: replies target threads as they exist now, not as they existed an hour ago.
4. Verify the parent after posting
Read back each reply and confirm its parent thread matches the intended target ID. Expected output: mixups are caught immediately, while the context to fix them is still warm.
5. Handle the resolved-between-fetch-and-reply case explicitly
Resolution does not block replies on GitHub. Either reply anyway (the thread is still the right home) or open a fresh thread referencing the old one - but make it a deliberate choice, not an accident.
Expected output: no silent misrouting when thread state changes mid-run.
Tool compatibility
- GitHub GraphQL API:
reviewThreadsnode IDs plusaddPullRequestReviewThreadReplyfor in-thread replies. - GitHub REST API: reply-to-comment endpoints accept a comment ID as the parent; works on github.com and GHES.
- gh CLI 2.x:
gh api graphqlfor the thread fetch from scripts.
Variant phrasings
bot replied to the wrong PR comment
Same fix. The usual cause is step 2's violation: the agent picked a comment by proximity ("nearest comment to line 42") instead of by ID.
review follow-ups in the wrong thread
When follow-ups drift across a long conversation, re-run step 3 before each follow-up batch; thread maps go stale fastest on active PRs.
thread ID confusion in review automation
If IDs are being mixed up (not just misresolved), check that the map keys thread IDs and not array indices - re-sorted lists silently reassign index-based targets.
Why it happens
Threads are addressed by opaque IDs, but agents reason in files and lines, so pipelines take a shortcut: find the thread "at" a line. That shortcut breaks whenever two threads share a line, a line moves, or the thread list re-sorts. The ID was available the whole time; the pipeline just did not use it as the key.
Edge cases
- Threads on outdated diffs: the ID is still valid for replies; GitHub shows them in context.
- Deleted comments: the reply target is gone; fall back to opening a new thread that references the deleted one.
- Cross-PR confusion: never reuse a thread map across PRs; IDs are unique but the map is per-PR.
- Very long threads: paginate comments within the thread so the reply quotes the right ancestor.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_SVRiN-85cqc3VqQOX-MZbA