Conversation
A 401 on the last retry still refreshed the token and asked for another attempt, so the loop ended with "Exhausted all retry attempts" instead of the 401 and its auth guidance. Co-authored-by: Cursor <cursoragent@cursor.com>
Callers can send a request exactly once (retry: false) for mutations whose side effects happen before a failure can be reported, and bypass the local response cache (cache: "no-store") for preflight reads that authorize a mutation. The default shared fetch is unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
betegon
added a commit
that referenced
this pull request
Sep 29, 2026
Keep sentry-client.ts identical to #1649 so merging it leaves no diff here. A final-attempt 401 now returns the response, which makes retry: false a plain single-attempt loop without its own code path. Co-authored-by: Cursor <cursoragent@cursor.com>
BYK
marked this pull request as ready for review
September 29, 2026 07:11
Member
|
Looks fine but we need the "why" of this change in the PR description. Why do we need this exactly? |
Contributor
|
Mention |
Member
Author
|
Oops, I was splitting up the link/unlink external issues PR (#1559) and it got a bit out of hand; this could have stayed in that PR. We need it there for two things: the Sentry App link callback runs before Sentry stores the association, so our default retries could fire it up to three times, and the link/unlink preflight reads can't come from the response cache, or |
This branch was successfully deployed
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.
Summary
Adds optional per-request controls to
getSdkConfig(regionUrl, options):retry: falsesends the request exactly once: no retry on 408/429/5xx, network errors or timeouts, and no 401 refresh-and-replay.cache: "no-store"skips both the lookup and the write in the local response cache.Callers that pass no options keep the shared memoized fetch. Both options exist for
sentry issue link/unlink(#1559).Why
retry: false. Linking through a Sentry App (Linear, for example) goes throughPOST /sentry-app-installations/{uuid}/external-issue-actions/. Sentry calls the App's webhook synchronously and only then stores the association, so the external tracker may already have acted when the request fails with a 5xx, a timeout or a dropped connection. The shared fetch retries every method on those failures, up to twice, so oneissue linkcould run the App's callback up to three times. The backend guard from getsentry/sentry#124069 turns a retry after a stored link into a no-op, but it cannot help when the callback ran and the write did not, and it explicitly does not promise exactly-once callbacks. For this request the CLI should report the failure and leave re-running to the user. Dropping the 401 replay there is harmless: a 401 is rejected before the endpoint runs, so the user just sees the auth error.cache: "no-store".issue link/unlinkread the issue's current associations to decide what to send:unlinkmaps the URL to the stored association ID, andlinkuses the stored canonical URL as itsexpectedExternalIssueUrlguard. By default those GETs fall into the response cache's 60-second issue tier (5 minutes for Sentry App installations, components and choice lookups). If someone links the issue in the web UI after the CLI last read the list, a cached read makesunlinkreport "already unlinked" and leave the association in place, and--dry-runshows the wrong state. Skipping the write too keeps a pre-mutation snapshot out of the cache for later commands.--fresh(disableResponseCache()) doesn't fit: it is process-wide and never reset, so in SDK/library mode onesdk.issue.link()call would turn off cache reads for the rest of the host process.The 401 fix. While wiring
retry: falseI found that a 401 on the last attempt still refreshed the token and asked for another attempt, so the loop threwExhausted all retry attemptsinstead of returning the 401 and its auth guidance. The last attempt now returns the 401. That is also what letsretry: falsebe a plain single-attempt loop, without a separate code path.Validation
mainwithExhausted all retry attempts.retry: falsetests fail if the option is ignored; the 401 one uses a refreshable OAuth session, so it checks that no refresh happens.tsc --noEmitand lint pass. Unit suite: 473 files, 10,096 passed / 17 skipped (TZ=UTC).Split out of #1559.