#942 with_rate_limit executes a failing tool TWICE (tool exception caught by limiter fail-open branch)
Description
EditEARS SPEC:
- When a rate-limited tool raises an exception after the rate-limit check passed, the decorator shall propagate that exception and shall have invoked the tool exactly once.
- If the rate-limit check itself fails unexpectedly, then the decorator shall invoke the tool at most once.
FOUND 2026-10-16 in worker logs during #939 verification: 'Rate limiter error for tools.shell.command: Command docker version returned non-zero exit status 127 (allowing request)' followed by a second 'Executing shell command: docker version'. Cause: engine/tools/decorators/rate_limit.py wrapper calls 'return func(*args, **kwargs)' INSIDE the try; the generic 'except Exception' fail-open branch then calls func again. Affected: tools.http.request, tools.email.send, tools.shell.run, tools.llm.call (every failure = duplicate side effect, e.g. duplicate POST/email). Also seen earlier for tools.llm.call.
SYNTHESIS (bugfix, single line): domain = decorator control flow; concept = separate guard evaluation from guarded call (check in try, call outside). Fail-open semantics of the check itself are out of scope here (#928 moves to TokenGate fail-closed).
Comments
Loading comments...
Context
Loading context...
Audit History
View AllLoading audit history...