Bug type
Behavior bug (incorrect output/state without crash)
Beta release blocker
No
Summary
The generic_repeat loop detector only checks warningThreshold and always returns level: "warning". It never checks criticalThreshold, so the most common loop pattern (same tool, same arguments, repeated calls) can never be blocked — only warned. The documentation states criticalThreshold is "threshold for blocking repetitive loop patterns" but this does not apply to generic_repeat.
Steps to reproduce
- Enable loop detection with default thresholds (
warningThreshold: 10, criticalThreshold: 20, globalCircuitBreakerThreshold: 30).
- Configure an agent that calls a non-polling tool (e.g.,
exec, read, web_fetch) with identical arguments repeatedly.
- Observe that after 10 calls, a warning is emitted. After 20 calls, another warning is emitted (not a block). The session continues indefinitely.
- Verify in source code (
src/agents/tool-loop-detection.ts, function detectToolCallLoop) that the generic_repeat detector only checks warningThreshold and never references criticalThreshold.
Expected behavior
Per the documentation (docs/tools/loop-detection.md), criticalThreshold is described as "threshold for blocking repetitive loop patterns." The generic_repeat detector should escalate to level: "critical" (which blocks the tool call) when recentCount >= criticalThreshold, consistent with how known_poll_no_progress and ping_pong detectors behave.
Actual behavior
The generic_repeat detector only checks warningThreshold and always returns level: "warning". The criticalThreshold value is never referenced in the generic_repeat code path. The source code comment explicitly states // Generic detector: warn-only for repeated identical calls.
Detector behavior comparison:
| Detector |
warningThreshold |
criticalThreshold |
globalCircuitBreaker |
global_circuit_breaker |
— |
— |
✅ Blocks (requires same args + same result) |
known_poll_no_progress |
⚠️ Warns |
✅ Blocks |
— |
ping_pong |
⚠️ Warns |
✅ Blocks (with noProgressEvidence) |
— |
generic_repeat |
⚠️ Warns |
❌ Not checked |
❌ Not checked |
OpenClaw version
2026.3.24 (cff6dc9)
Operating system
Ubuntu 22.04.5 LTS (Linux 5.15.0-173-generic, x64)
Install method
npm global
Model
Not model-specific (affects all models — this is a gateway-level loop detection issue)
Provider / routing chain
N/A (gateway-level, before provider routing)
Additional provider/model setup details
No response
Logs, screenshots, and evidence
Impact and severity
- Affected: All users with loop detection enabled who encounter non-polling tool loops (the most common runaway pattern)
- Severity: High — the primary protection mechanism has a gap for the most common loop type
- Frequency: Always —
generic_repeat never blocks regardless of threshold settings
- Consequence: Runaway token spend and session lockups. The
global_circuit_breaker does not catch these loops because it requires identical results (not just identical arguments), so loops with varying output bypass it entirely. The only effect is a warning message injected into the agent's context, which the agent may ignore.
Additional information
Suggested fix: Add criticalThreshold escalation to the generic_repeat detector. When recentCount >= criticalThreshold, return level: "critical" instead of level: "warning". This aligns with the documented behavior and closes the protection gap.
Alternatively, update the documentation to clarify that criticalThreshold only applies to known_poll_no_progress and ping_pong detectors, and that generic_repeat is intentionally warn-only. However, this leaves a significant gap in loop protection.
Relevant source files:
src/agents/tool-loop-detection.ts — detectToolCallLoop() function, lines 344-360
docs/tools/loop-detection.md — criticalThreshold field description
Config used during observation:
{
"tools": {
"loopDetection": {
"enabled": true,
"historySize": 30,
"warningThreshold": 3,
"criticalThreshold": 4,
"globalCircuitBreakerThreshold": 5
}
}
}
Bug type
Behavior bug (incorrect output/state without crash)
Beta release blocker
No
Summary
The
generic_repeatloop detector only checkswarningThresholdand always returnslevel: "warning". It never checkscriticalThreshold, so the most common loop pattern (same tool, same arguments, repeated calls) can never be blocked — only warned. The documentation statescriticalThresholdis "threshold for blocking repetitive loop patterns" but this does not apply togeneric_repeat.Steps to reproduce
warningThreshold: 10,criticalThreshold: 20,globalCircuitBreakerThreshold: 30).exec,read,web_fetch) with identical arguments repeatedly.src/agents/tool-loop-detection.ts, functiondetectToolCallLoop) that thegeneric_repeatdetector only checkswarningThresholdand never referencescriticalThreshold.Expected behavior
Per the documentation (
docs/tools/loop-detection.md),criticalThresholdis described as "threshold for blocking repetitive loop patterns." Thegeneric_repeatdetector should escalate tolevel: "critical"(which blocks the tool call) whenrecentCount >= criticalThreshold, consistent with howknown_poll_no_progressandping_pongdetectors behave.Actual behavior
The
generic_repeatdetector only checkswarningThresholdand always returnslevel: "warning". ThecriticalThresholdvalue is never referenced in thegeneric_repeatcode path. The source code comment explicitly states// Generic detector: warn-only for repeated identical calls.Detector behavior comparison:
global_circuit_breakerknown_poll_no_progressping_ponggeneric_repeatOpenClaw version
2026.3.24 (cff6dc9)
Operating system
Ubuntu 22.04.5 LTS (Linux 5.15.0-173-generic, x64)
Install method
npm global
Model
Not model-specific (affects all models — this is a gateway-level loop detection issue)
Provider / routing chain
N/A (gateway-level, before provider routing)
Additional provider/model setup details
No response
Logs, screenshots, and evidence
Impact and severity
generic_repeatnever blocks regardless of threshold settingsglobal_circuit_breakerdoes not catch these loops because it requires identical results (not just identical arguments), so loops with varying output bypass it entirely. The only effect is a warning message injected into the agent's context, which the agent may ignore.Additional information
Suggested fix: Add
criticalThresholdescalation to thegeneric_repeatdetector. WhenrecentCount >= criticalThreshold, returnlevel: "critical"instead oflevel: "warning". This aligns with the documented behavior and closes the protection gap.Alternatively, update the documentation to clarify that
criticalThresholdonly applies toknown_poll_no_progressandping_pongdetectors, and thatgeneric_repeatis intentionally warn-only. However, this leaves a significant gap in loop protection.Relevant source files:
src/agents/tool-loop-detection.ts—detectToolCallLoop()function, lines 344-360docs/tools/loop-detection.md—criticalThresholdfield descriptionConfig used during observation:
{ "tools": { "loopDetection": { "enabled": true, "historySize": 30, "warningThreshold": 3, "criticalThreshold": 4, "globalCircuitBreakerThreshold": 5 } } }