Skip to content

set -e kills the whole loop on any non-zero driver return (429/limit), bypassing retry ladder #204

Description

@nickvorobiov

Summary

Under set -e, a single non-zero driver return (e.g. a transient Anthropic 429 "Server is temporarily limiting requests") kills the entire Ralph loop instead of hitting the retry/api-limit/circuit-breaker ladder. The 30s-retry, 5-hour-limit wait, and circuit-breaker branches are effectively dead code.

Affects ralph/ralph_loop.sh on main (line ~2888) and in the published v2.11.0.

Root cause

ralph_loop.sh sets set -e globally (line 7), then invokes the driver as a bare command:

# Execute Claude Code
execute_claude_code "$loop_count"      # returns 1 on ANY driver failure
local exec_result=$?                    # never reached on failure

execute_claude_code returns non-zero on failure (1 generic, 2 API 5-hour limit, 3 circuit breaker). Under set -e, a bare simple command that returns non-zero exits the script immediately — before exec_result is captured — so the whole if/elif/else ladder that inspects exec_result (retry, api-limit wait, circuit-breaker handling) is never executed. The _on_exit trap then reports:

ERROR  Ralph loop exiting unexpectedly: error (code 1)

Minimal repro (bash semantics)

$ bash -c 'set -e; trap "echo TRAP code=$?" EXIT; f(){ return 1; }; f; echo "after f"'
TRAP code=1        # "after f" never prints

Real-world trigger

A transient server-side 429 (not a usage cap) is enough. Observed driver result JSON:

{"is_error":true,"api_error_status":429,
 "result":"API Error: Server is temporarily limiting requests (not your usage limit) · Rate limited"}

The CLI exits 1 → loop dies. A backoff-and-retry would have recovered on the next attempt.

Fix

Guard the call so set -e doesn't fire and the exit code is preserved:

# Execute Claude Code
local exec_result=0
execute_claude_code "$loop_count" || exec_result=$?

One line changed (plus a defensive exec_result=0 init). This lets control reach the existing ladder so return codes 1/2/3 are handled as designed. Verified bash -n clean.

Environment

  • bmalph 2.11.0 (Homebrew/npm, latest)
  • macOS (Darwin 25.2.0), bash driving the loop

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions