Stop futile auth retries in Copilot/Claude/Codex harnesses after first-attempt authentication failure#33093
Merged
Merged
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix Copilot CLI retry loop after unsetting GitHub token
Stop futile auth retries in Copilot/Claude/Codex harnesses after first-attempt authentication failure
May 18, 2026
pelikhan
approved these changes
May 18, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Hardens retry behavior in the Copilot/Claude/Codex harnesses by treating first-attempt authentication failures as non-retryable, reducing noisy/futile retry loops and improving per-attempt diagnostics.
Changes:
- Added
isAuthenticationFailedError(...)detection + first-attempt no-retry short-circuit incopilot_harness.cjs,claude_harness.cjs, andcodex_harness.cjs, and surfacedisAuthenticationFailedErrorin structured per-attempt logs. - Updated/added unit tests to cover the new auth-failure detection and “no retry on attempt 1” policy.
- Updated
.github/workflows/pr-description-caveman.lock.yml(large generated workflow lockfile changes).
Show a summary per file
| File | Description |
|---|---|
| actions/setup/js/copilot_harness.cjs | Adds auth-failure detection helper, exports it, logs the new flag, and breaks retries on first-attempt auth failure. |
| actions/setup/js/copilot_harness.test.cjs | Adds tests for auth-failure detection and first-attempt no-retry behavior. |
| actions/setup/js/claude_harness.cjs | Adds auth-failure detection helper/export, logs the new flag, and breaks retries on first-attempt auth failure. |
| actions/setup/js/claude_harness.test.cjs | Adds tests for the new auth-failure detection and retry policy behavior. |
| actions/setup/js/codex_harness.cjs | Adds auth-failure detection helper/export, logs the new flag, and breaks retries on first-attempt auth failure. |
| actions/setup/js/codex_harness.test.cjs | Adds tests for the new auth-failure detection and first-attempt no-retry behavior. |
| .github/workflows/pr-description-caveman.lock.yml | Regenerates/updates the workflow lockfile (versions, steps, and runtime details). |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 7/7 changed files
- Comments generated: 7
Comment on lines
+90
to
+92
| // After a first-attempt auth failure, retrying is futile because the entrypoint unsets | ||
| // COPILOT_GITHUB_TOKEN between attempts. | ||
| const AUTHENTICATION_FAILED_PATTERN = /Authentication failed(?:\s*\(Request ID:[^)]+\))?/i; |
| // - embedded stream-json result fields (e.g. "api_error_status":429) | ||
| // - human-readable message text ("rate limit") | ||
| const RATE_LIMIT_ERROR_PATTERN = /rate_limit_error|429 Too Many Requests|"api_error_status"\s*:\s*429|request rejected \(429\)|rate limit/i; | ||
| const AUTHENTICATION_FAILED_PATTERN = /Authentication failed(?:\s*\(Request ID:[^)]+\))?/i; |
| // Matches "rate_limit_exceeded" from the OpenAI error type field and the "429" status code | ||
| // that Codex emits when the API rate limit is hit. | ||
| const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError/i; | ||
| const AUTHENTICATION_FAILED_PATTERN = /Authentication failed(?:\s*\(Request ID:[^)]+\))?/i; |
| it("matches authentication failed with request id", () => { | ||
| expect(isAuthenticationFailedError("Authentication failed (Request ID: C818:3ED713:19D401B:1C446B7:69D653CA)")).toBe(true); | ||
| }); | ||
|
|
Comment on lines
+89
to
99
| - name: Checkout actions folder | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| repository: github/gh-aw | ||
| sparse-checkout: | | ||
| actions | ||
| persist-credentials: false | ||
| - name: Setup Scripts | ||
| id: setup | ||
| uses: github/gh-aw-actions/setup@v0.72.1 | ||
| uses: ./actions/setup | ||
| with: |
Comment on lines
+93
to
+101
| describe("isAuthenticationFailedError", () => { | ||
| it("returns true for authentication failed with request id", () => { | ||
| expect(isAuthenticationFailedError("Authentication failed (Request ID: C818:3ED713:19D401B:1C446B7:69D653CA)")).toBe(true); | ||
| }); | ||
|
|
||
| it("returns false for non-authentication-failed output", () => { | ||
| expect(isAuthenticationFailedError("No authentication information found")).toBe(false); | ||
| expect(isAuthenticationFailedError("rate_limit_exceeded")).toBe(false); | ||
| }); |
|
|
||
| it("returns false for unrelated output", () => { | ||
| expect(isAuthenticationFailedError("No authentication information found")).toBe(false); | ||
| expect(isAuthenticationFailedError("rate_limit_error")).toBe(false); |
This was referenced May 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Retry loops in the harnesses were optimized for transient partial-execution failures, but they also retried after first-attempt auth failures. In workflows where entrypoint cleanup removes token-based auth between attempts, this produced guaranteed follow-on failures and noisy diagnostics.
Retry policy hardening (first-attempt auth failures)
Authentication failed (Request ID: ...)in:actions/setup/js/copilot_harness.cjsactions/setup/js/claude_harness.cjsactions/setup/js/codex_harness.cjsattempt === 0), treating it as non-retryable.Operational diagnostics
isAuthenticationFailedErrorto make retry decisions obvious in run logs.Focused test updates