Troubleshooting
Most issues fall into a small set of patterns. The dashboard is your first stop — it shows the last 50 reviews for your workspace with each review’s state, trigger, and any error message.
Reading the state
Section titled “Reading the state”Every review moves through: queued → fetching_config → reviewing → publishing → done, with failed as the other terminal state.
- Stuck in
queued— the review hasn’t been picked up. Across all PRs, this means the review controller isn’t running (self-host: check the controller deployment). For a single PR, give it a moment past the poll interval. - Stuck in
reviewing— a model call is taking a while; large PRs take longer. The error surfaces on the row if it ultimately fails. failed— the row carries an error message inline on the dashboard. A failed diff fetch or summary call fails the whole review; per-file failures don’t.
No review fired on a fresh PR
Section titled “No review fired on a fresh PR”Check, in order:
- Is
.destesi.ymlon your default branch? Code review ignores the file on the PR branch — that’s deliberate. See Concepts. The change only takes effect once merged. - Is
review.enabled: trueset explicitly? Without it thereviewblock is a no-op. - Does the file parse? A malformed file surfaces a parse error (see below). Watch for unquoted globs containing
*, or a mistyped enum value likenits: shout. - Is the Destesi GitHub App installed on this repo, with GitHub connected for your workspace? Connect the GitHub credential once in Connect and install the App on the repo from Connect’s GitHub page (
connect.destesi.io/workspace/providers/github). An App installed straight from GitHub’s own install URL is not linked to any workspace — the App looks installed on GitHub’s side while no review ever fires. Re-run the install from Connect to bind it. The dashboard shows your workspace’s GitHub connection state. - Is the PR in scope? A draft PR is skipped unless
scope.drafts: true; a base branch outsidescope.base_branchesis skipped.
The Check shows a parse error
Section titled “The Check shows a parse error”If .destesi.yml on the default branch is malformed, the reviewer can’t read its policy. The most common causes are an unquoted glob (paths: [**/*.go] → quote it: ["**/*.go"]), an invalid enum (nits, fail_check_on, approve_on, a chat.commands entry, an allowed_associations value, or a model provider outside the allowed set), or a version other than 1. Fix the file on the default branch and the next event re-reads it.
A review ran but inline comments are missing
Section titled “A review ran but inline comments are missing”Only a summary appeared. One of:
output.inline: falsein your config.- Every changed file was excluded by an ignore or scope rule (the summary’s “skipped files” footer will say so).
- The per-file model calls failed and were dropped as
review_failed(also in the footer) — safe to retry with@destesi review. output.nits: hidecombined with a review that found only nit-level issues — those are dropped from the inline review.
Some files were skipped
Section titled “Some files were skipped”The summary ends with a “Skipped files” footer counting the drops by reason:
| Reason | Meaning |
|---|---|
ignored |
Matched defaults.ignore.paths or scope.paths.exclude. |
out_of_scope |
Not in a non-empty scope.paths.include list. |
file_limit |
The pull request changed more files than one review may send to the model (25 by default). The file was not reviewed. |
diff_limit |
The whole-PR diff exceeded the byte budget (2 MiB), so this file’s section was never parsed. The file was not reviewed. |
content_truncated |
The file was reviewed, but its head content and/or diff hunks were cut down to fit the per-file prompt budget — so that file’s review is partial, not absent. |
review_failed |
The per-file model call failed. Retry with @destesi review. |
Everything except content_truncated means the file never reached the model at all. If you’re hitting file_limit or diff_limit regularly, the fix is a narrower pull request — split it, or exclude generated and vendored paths via defaults.ignore.paths so your real changes fit inside the budget. Reviews older than these limits may still carry a truncated reason; it is the previous name for file_limit.
@destesi <command> got no reply
Section titled “@destesi <command> got no reply”- Do you have write access? Commands are honoured only from comment authors whose GitHub association is OWNER, MEMBER, or COLLABORATOR. Anyone else is silently ignored — no reply, no reaction — by design. See Reference → Chat commands.
- Is the mention at the start of a line?
@destesimust lead the line (after optional whitespace). A mention buried mid-sentence or inside quoted text won’t trigger. - Self-host: is the GitHub App subscribed to
issue_commentandpull_request_review_commentevents, with the Issues (read) permission accepted on the installation? Without those, comment events never reach the reviewer. See Reference → GitHub App requirements.
@destesi ignore didn’t work
Section titled “@destesi ignore didn’t work”- “I can’t read the rule id off that comment” — you replied to something that isn’t one of the bot’s own inline comments (likely the summary or another person’s reply). Reply directly to one of the reviewer’s line comments; those carry the hidden marker it needs.
- The same comment came back after ignoring it — overrides are keyed by
(installation, repo, path, rule_fingerprint). If the file moved (different path) or the finding text shifted enough to change its fingerprint, the override no longer matches. Reply@destesi ignoreagain on the new comment.
@destesi review says it already re-reviewed this commit
Section titled “@destesi review says it already re-reviewed this commit”The reply “I’ve already re-reviewed this commit the maximum number of times. Push a new commit and I’ll review it fresh.” means you’ve spent the re-run budget for this head commit — 3 re-runs per commit by default.
The budget exists because a re-review of an unchanged commit buys the same answer at the same cost, so re-running in a loop is pure spend. Push a commit and it resets, since a new head SHA is new work. Automatic reviews don’t consume it — only @destesi review does. See Reference → Re-review limits.
@destesi review says it has no head SHA
Section titled “@destesi review says it has no head SHA”The reviewer re-runs against the head SHA from the PR’s most recent review. If it has never reviewed this PR, it has no SHA recorded and asks you to push a commit (which fires the auto-review) or wait for it. Push any commit, or open the PR fresh.
The Check is red and you disagree with the finding
Section titled “The Check is red and you disagree with the finding”Either lower output.fail_check_on from severe to never (the Check stays informational and never blocks), or reply @destesi ignore on the specific finding to suppress it on future reviews. If a whole category of finding is wrong for your codebase, add a counter-instruction to your guidance block — for example, “We use errors.New, not fmt.Errorf — do not flag this.” See Reference → Writing effective instructions.
The reviewer keeps flagging something that’s fine for us
Section titled “The reviewer keeps flagging something that’s fine for us”Two steps: @destesi ignore for the immediate noise, then add the rule to your default-branch .destesi.yml so it sticks across PRs. Ignores handle one finding on one path; an instruction handles the whole pattern.
Still stuck?
Section titled “Still stuck?”Hosted users: contact support with the review id from the dashboard. Self-hosters: check the API logs and the review controller logs for review-prefixed lines, and confirm REVIEW_ENABLED is set on the API process.