-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
I ran into this problem on a closed-source project that uses this action. Investigation with Claude Code turned up the following recommendation.
Problem
When Claude Code hits a rate limit, the SDK streams a rate_limit_event message followed by a result message with is_error: true, then throws. Because the execution file write in base-action/src/run-claude-sdk.ts is after the try/catch block (not in a finally), the file is never written and the execution_file output is empty.
This means callers cannot distinguish rate limits from other failures — both surface as exit code 1 with a minified SDK stack trace.
Where
base-action/src/run-claude-sdk.ts lines ~160–188:
try {
for await (const message of query({ prompt, options: sdkOptions })) {
messages.push(message);
// ... messages are collected, including rate_limit_event and result
}
} catch (error) {
console.error("SDK execution error:", error);
throw new Error(`SDK execution error: ${error}`);
// ← execution file write below is unreachable
}
// This block never executes on rate limit errors
const result: ClaudeRunResult = { conclusion: "failure" };
try {
await writeFile(EXECUTION_FILE, JSON.stringify(messages, null, 2));
result.executionFile = EXECUTION_FILE;
} catch (error) {
core.warning(`Failed to write execution file: ${error}`);
}Suggested fix
Move the execution file write into a finally block. The messages array is populated before the throw, so the data is available:
} catch (error) {
console.error("SDK execution error:", error);
throw new Error(`SDK execution error: ${error}`);
} finally {
if (messages.length > 0) {
try {
await writeFile(EXECUTION_FILE, JSON.stringify(messages, null, 2));
core.setOutput("execution_file", EXECUTION_FILE);
} catch (e) {
core.warning(`Failed to write execution file: ${e}`);
}
}
}Additionally, a dedicated error_type output (e.g. rate_limit) would let workflows handle rate limits without grepping JSON — but the execution file alone would unblock the use case.
Impact
Workflows using continue-on-error: true to post-process failures cannot detect rate limits vs real errors, making it impossible to:
- Show a warning annotation instead of a hard failure
- Surface the reset time to PR authors
- Skip re-runs that will hit the same limit
Reproduction
Trigger a code review while rate-limited. The execution_file output is empty and the only signal is the generic SDK execution error: Error: Claude Code process exited with code 1 in the step log.