anthropics / anthropics/claude-code-action

Post-result num_turns > maxTurns guard can reject batched-tool traces within the round-trip limit

Open
#1,758 0 comments 0 reactions 0 assignees View on GitHub
bug p2
Dominant language
TypeScript
Stars
8.9k
Forks
2.1k
PR merge metrics
PR metrics pending

Description

# Post-result num_turns > maxTurns guard can reject batched-tool traces within the model round-trip limit

Follow-up to #1607 and #1577. This report questions the post-result counter comparison, not the typed maxTurns mapping or the need to fail on genuine SDK errors.

At the inspected main revision `a874e9ecd7bb36efdad65429c6b35815f5a08f10` (Claude Code 2.1.251 / declared Agent SDK dependency `^0.3.251`), [run-claude-sdk.ts](https://github.com/anthropics/claude-code-action/blob/a874e9ecd7bb36efdad65429c6b35815f5a08f10/base-action/src/run-claude-sdk.ts#L238-L250) rejects success when `result.num_turns > sdkOptions.maxTurns`. Official agent-loop docs define `maxTurns` as tool-use round trips. Those quantities can differ with batched tool calls.

## Existing local evidence

An existing direct CLI 2.1.251 run requested `--max-turns 14` and returned `success / is_error:false / num_turns:27`. Metadata from the original request only shows:

- one user input, no subagents or resumed input in the analyzed interval;
- 14 distinct main assistant response IDs;
- 13 responses containing tool calls, plus the final response;
- 26 distinct tool calls and 26 matching tool results.

It fits 14 even counting the final response. Counts were obtained by grouping assistant records by `message.id`, deduplicating `tool_use.id`, and matching tool-result IDs within the original request interval. The subsequent resumed request was excluded.

The action's exact predicate rejects this result as an overrun. We reproduced that predicate behavior offline without another model request. This is local CLI metadata plus a wrapper-predicate reproduction, not a freshly instrumented hosted SDK run. The equality of `num_turns` to tool calls plus one in this trace is an observation, not a proposed universal conversion formula.

## Hosted symptom and limits of attribution

[A hosted run at the same action pin](https://github.com/goformx/goformx/actions/runs/33340103680) logs typed `maxTurns:16`, `success / is_error:false / num_turns:28`, zero permission denials and 328658 ms runtime. The native final review is posted, then the guard fails the job. That run's raw trace was not retained, so its exact model-round count remains unknown; it is consistent with the mismatch but is not the proof of the 14/27 counting above.

## Requested correction

The [current regression test](https://github.com/anthropics/claude-code-action/blob/a874e9ecd7bb36efdad65429c6b35815f5a08f10/base-action/test/run-claude-sdk.test.ts#L221-L277) mocks `num_turns:73 / maxTurns:60` without model-response/tool-call structure. Please add a batching-aware fixture and establish which result/stream metric is comparable to `maxTurns`. Preserve typed `maxTurns` enforcement, genuine `error_max_turns`, `is_error` handling and timeouts; do not resolve this by raising budgets or blindly accepting failures.

Reference contract: [official agent-loop documentation](https://code.claude.com/docs/en/agent-sdk/agent-loop). Its turns/budget section describes tool-use round trips, and its result section distinguishes success from `error_max_turns`.

No credentials or raw repository/model transcripts are included. A fresh SDK/model-backed reproduction has not been run as part of this report.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.