Skip to content

execution_file output not written when SDK throws on error_max_turns #1226

@dhendry

Description

@dhendry

Bug Description

When Claude Code reaches the maximum number of turns (error_max_turns), the execution_file output is not written to disk. The execution data (messages, cost, turn count, duration) is accumulated in memory and the result object is printed to stdout, but the file at $RUNNER_TEMP/claude-execution-output.json is never created.

Root Cause

In base-action/src/run-claude-sdk.ts, the file write happens after the for await loop's try/catch block:

try {
  for await (const message of query(...)) {
    messages.push(message);
    // ...
  }
} catch (error) {
  console.error("SDK execution error:", error);
  throw new Error(`SDK execution error: ${error}`);
}

// This code is never reached when the SDK throws
try {
  await writeFile(EXECUTION_FILE, JSON.stringify(messages, null, 2));
  result.executionFile = EXECUTION_FILE;
} catch (error) {
  core.warning(`Failed to write execution file: ${error}`);
}

When the SDK throws (e.g., Claude Code returned an error result: Reached maximum number of turns), the catch block re-throws before the writeFile call is reached.

Impact

  • The execution_file output is empty, so downstream steps that depend on it (e.g., extracting cost, turn count, duration, tool error counts) get no data
  • The result object is printed to stdout (with num_turns, total_cost_usd, duration_ms, subtype: "error_max_turns"), but the file is absent — consumers can't access the structured data
  • This affects any workflow that uses steps.<id>.outputs.execution_file for post-run metrics or diagnostics

Expected Behavior

The execution file should be written regardless of whether the SDK throws. The messages array is already populated with all conversation turns up to the point of failure — writing it to disk before re-throwing preserves diagnostic data.

Suggested Fix

Move the writeFile call into a finally block, or write the file in the catch block before re-throwing:

} catch (error) {
  console.error("SDK execution error:", error);
  // Write partial execution data before re-throwing
  try {
    await writeFile(EXECUTION_FILE, JSON.stringify(messages, null, 2));
    result.executionFile = EXECUTION_FILE;
  } catch (writeError) {
    core.warning(`Failed to write execution file: ${writeError}`);
  }
  throw new Error(`SDK execution error: ${error}`);
}

Environment

  • claude-code-action@v1 (SHA: 905d4eb99ab3d43143d74fb0dcae537f29ac330a)
  • Bedrock mode with --max-turns set

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingp2Non-showstopper bug or popular feature request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions