anomalyco / anomalyco/opencode
subagent: infinite loop of identical tool calls for ~50min with no loop protection, uncontrollable token burn
@rekram1-node is already working on this.
Since Aug 27, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Subagent infinite loop: repeated identical tool calls for ~50 min, no loop protection, uncontrollable token burn
Summary
A background general subagent entered an infinite loop: it issued 364 identical grep tool calls (same pattern, same path, same directory) over ~50 minutes with a steady ~5s cadence, burning ~184k input tokens + ~40k output tokens + ~142M cache-read tokens before I manually discovered and interrupted it. OpenCode's agent loop has no repeated-action detection, no step limit, no heartbeat timeout, and the parent session has no way to notice or abort a stuck subagent — it was reported as running the whole time.
Environment
- opencode version: 0.0.0-beta-18286 (opencode --version reports 1.18.18)
- OS: Darwin 25.5.0 (macOS 26.5.1, arm64)
- Terminal: Unavailable: terminal environment variables are not set (running via OpenCode Beta desktop app)
- Shell: /bin/zsh
- Install/channel: beta (OpenCode Beta.app, CLI path
.../cli/0.0.0-beta-18286/opencode-cli serve --service) - Active plugins: None found in config
- Model: a deepseek-v4-flash variant (via a private/custom OpenAI-compatible provider; details redacted for privacy)
Reproduction
- Start a parent session (TUI/desktop).
- Spawn a background subagent (
generalagent) with a large task — in my case: "review a 47KB / 21-file merge request diff", where the subagent cross-verifies claims against source code. - Let it run. The subagent loads a large context (cache-read peaked at ~142M tokens total over the loop) and enters a degenerate mode where it repeatedly decides to execute the same grep call: pattern
ErrsSceneConfigNotFound|ErrsSceneConfigFailed, path.../PlanServer, every ~5 seconds. - Observe: 364 consecutive messages with identical tool input, zero progress, session stays
runninginGET /api/session/active.
Expected Behavior
- OpenCode should detect repeated identical tool calls (or a step/iteration cap, or a per-session max duration) and either stop the loop, surface a warning to the parent session, or expose a configurable limit.
- The parent session / API should expose a way to notice a stuck subagent (e.g., heartbeat, last-activity timestamp in session data) and abort it without requiring the user to inspect the raw session database.
- Background subagents that burn tokens with no progress should not be reported indefinitely as
running.
Actual Behavior
- The subagent ran 364 identical grep calls at a ~5.0s cadence (sampled intervals: 5,5,5,5,5,6,4,6,5,5) for ~50 minutes (10:04:37 → 10:54:26 local).
- Token burn during the loop: ~184,196 input + ~39,518 output + ~142,413,184 cache-read tokens (from session DB).
- No built-in detection, limit, warning, or auto-interrupt.
GET /api/session/activereported{"ses_...": {"type": "running"}}throughout. - I had to discover the loop by querying the SQLite DB (
~/.local/share/opencode/opencode.db, tablesession_message) for repeated tool calls, then manually callPOST /api/session/{id}/interruptusing the authenticated HTTP API (credentials from the local service config).
Additional Context
- Root cause of the repetition is model behavior (a long-context degenerate repetition), but the framework provides zero protection against it — that is the bug.
- I could not find any documented step limit / max-turns / loop-detection / heartbeat configuration in the config schema; only
reasoningEffortvariants are present in the provider config. - Interrupt endpoint exists (
POST /api/session/{sessionID}/interrupt) and works, but it is purely manual/out-of-band; nothing in the framework triggers it. - Frequency: observed once so far; reproducible trigger appears to be a long-running background subagent with repeated verification tool calls.
- Workaround used: manual SQLite inspection + manual HTTP interrupt via
opencode2 api post /api/session/{id}/interrupt(or raw curl with Basic auth).
Suggested directions (for maintainers):
- Add a loop guard: N consecutive identical tool calls (same name + same input hash) → warn or abort (configurable).
- Add a step/iteration cap per agent turn loop (e.g.,
maxSteps) with a clear terminal state instead ofrunning. - Surface last-activity/heartbeat per session in the API so parents/clients can detect stalls.
- Allow cancelling background subagents from the parent session UI/API.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.