Worker & Pipeline Issues
For connectivity and auth issues, see Connectivity & Auth. For common failures and diagnostics overview, see the Troubleshooting page.
Worker Timeouts
A worker timeout means a FORGE, SENTINEL, or VESSEL workspace did not finish its assigned step within the configured timeout. Timeouts are usually caused by one of three things: a long LLM call, a hung MCP server, or a workspace that failed to provision.
# Find worker workspace for a ticket coder ws ls | rg 'forge-1-my-team' # SSH into it and inspect processes coder ssh forge-1-my-team ps aux | rg -i 'claude|codex|aider' tail -f /tmp/openflows-worker.log
Do not manually kill a healthy worker
SENTINEL Rejection Loops
A SENTINEL rejection loop occurs when SENTINEL repeatedly rejects a plan or segment and FORGE cannot satisfy the requested changes. This is the most common failure mode in the review phase. It is not a bug in SENTINEL; it is a sign that the specification is ambiguous or the implementation is hitting a genuine quality issue.
NEXUS tracks consecutive rejections for the same segment. After SENTINEL_REJECTION_LIMIT
(default 3), the ticket is escalated to AwaitingHuman with a STATUS.json blocker.
# Count rejections for a ticket in the log rg 'SENTINEL.*REJECTED' /tmp/openflows-controller.log | rg 'ISSUE-123' | wc -l # Read worker status to see rejection reason cat /tmp/workspaces/forge-1-my-team/STATUS.json | jq .errors
Merge Conflicts
VESSEL monitors the mergeable field of the PR. If it becomes false, VESSEL
retries after a backoff. If it remains false after several retries, the ticket is escalated.
| Cause | What to check |
|---|---|
| CI failing | VESSEL waits for CI to pass. Check PR checks on GitHub and CI provider logs. |
| Branch protection | GitHub branch protection rules may require reviews or status checks VESSEL cannot satisfy. |
| Merge conflict | Base branch has moved forward. NEXUS will reassign ticket or escalate. |
| Draft PR | VESSEL only merges non-draft PRs. FORGE may have opened PR as draft for manual review. |
| Unauthorized merge | Coder external auth identity lacks merge permission. Check repository settings. |
# Check PR mergeable state via GitHub CLI gh pr view 123 --repo owner/repo --json mergeable,state,reviewDecision,statusCheckRollup
How to Read STATUS.json
STATUS.json is a worker-written artifact that declares the current state of a
ticket. It is written at the end of every significant phase and whenever a worker
encounters a blocker. Operators should read it as the worker's own explanation of what
happened, not as a system-generated log.
{
"outcome": "blocked",
"phase": "review",
"ticket": "ISSUE-123",
"pr_url": null,
"blocker": {
"kind": "AmbiguousRequirement",
"description": "The ticket asks to 'refactor the parser' but does not specify which parsing rules must be preserved.",
"files_written": ["PLAN.md", "CONTRACT.md"],
"question_for_human": "Which edge cases in the current parser must remain unchanged?"
},
"errors": ["SENTINEL rejected segment 2: missing error handling for malformed input"],
"last_updated": "2026-07-20T15:43:21Z"
}| Field | Meaning |
|---|---|
outcome | One of in_progress, completed, failed, blocked, or awaiting_human. |
phase | Current pipeline phase: planning, implementing, review, pr_opened, merged. |
ticket | The issue or ticket ID associated with this status. |
pr_url | URL of the opened pull request, if any. |
blocker | When outcome is blocked, object describing blocker kind and question. |
errors | Array of recent error messages. Empty when healthy. |
last_updated | ISO timestamp of the last status write. |
| Blocker Kind | Meaning |
|---|---|
AmbiguousRequirement | Ticket description is unclear; NEXUS needs human to refine spec. |
DependencyNotMerged | Code dependency missing because prerequisite PR not yet merged. |
FileLockConflict | Another worker/process is holding a required file or resource. |
Other | Catch-all for blockers that do not fit above. Read description. |
Blocked is better than wrong
blocked status is a deliberate human escalation. It means the system
recognized it could not safely proceed and stopped. When you see a blocked status, answer
the question_for_human in the ticket, update the spec, and resume the tenant.
Do not bypass the blocker by editing Redis manually unless you understand the risk.
Escalation Checklist
If the above steps do not resolve the issue, gather the following information before escalating to NEXUS or another team:
- The exact tenant and ticket ID.
- The relevant
STATUS.jsonfrom the worker workspace. - The last 100 lines of
/tmp/openflows-controller.logfor the tenant. - The output of
openflows doctor --tenant {tenant}. - Whether the Coder AI Gateway and Redis are healthy.
- Whether the GitHub external auth link is active for the tenant user.
Preserve worker workspaces during incidents