Log the reason a token exchange fails in verbose output - #8216
Merged
Conversation
isaacroldan
reviewed
Jul 31, 2026
isaacroldan
reviewed
Jul 31, 2026
isaacroldan
reviewed
Jul 31, 2026
isaacroldan
reviewed
Jul 31, 2026
isaacroldan
reviewed
Jul 31, 2026
isaacroldan
reviewed
Jul 31, 2026
…anged Every app automation token exchange failure collapsed into a single fixed message, and the OAuth `error`/`error_description` returned by Identity were discarded before reaching it, so a revoked token, an expired token and an unreachable Identity were indistinguishable. Verbose output didn't help either: it printed the response headers for that call and no status or body. Keep the existing sentence as the headline and append the upstream reason when there is one, and log the status plus the OAuth error fields of a failed token request under `--verbose`. Only failed responses are logged, and only the `error`/`error_description` fields, since a successful body carries the access token.
The fields of a failed token response aren't guaranteed: the responder isn't always Identity, since proxies and gateways can answer with arbitrary JSON. A body without an `error` field crashed the error constructor before any message was shown, and `error_description` flowed into the terminal unbounded. Guard both fields once, where the response is parsed: `error` falls back to `unknown_error`, and `error_description` is flattened to a single line and capped at 200 characters. Every consumer downstream now gets the shape the type declares. Also widen the changeset wording: the shared error handler enriches interactive token errors too, not only automation-token ones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Map any code outside IdentityDeviceError to unknown_failure at the exchange boundary instead of casting, and add a default branch to the poll switch so an unexpected code rejects rather than leaving the promise unsettled. Also apply one shared flatten-and-truncate rule to both the Identity description and the appended Reason message. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review direction from the proposal thread: every token failure resolves to the same user action, so the default error stays generic and the reason lives in the debug log only. The debug line in tokenRequest covers OAuth rejections. The automation catch now logs the caught error too, which covers failures that produce no OAuth body, such as the authentication service being unreachable. The enrichment of InvalidGrantError, InvalidRequestError and the fall-through AbortError is reverted: session.ts only checks the class, so those messages carried the detail into default output for nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wes-shaw
force-pushed
the
automation-token-identity-error
branch
2 times, most recently
from
August 3, 2026 20:39
e0a9fd1 to
ba7c1b7
Compare
isaacroldan
reviewed
Aug 4, 2026
isaacroldan
approved these changes
Aug 5, 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.
WHY are these changes introduced?
When an app automation token exchange fails, the CLI prints
The custom token provided can't be used for the App Management API.with nothing about why. Identity's response carries an OAutherrorcode and anerror_descriptionthat provides more context but the CLI discards both. Anyone debugging a CI failure has to guess, or find someone with access to Identity's logs.All of these cases resolve to the same user action (create a fresh token), so the default error output does not need to change. The detail belongs in
--verboselogs, where app developers and support can read it without Identity-side access. That is the full scope of this PR: default output stays byte-identical tomain.WHAT is this pull request doing?
Adds two debug lines, both visible only with
--verbose:tokenRequestlogs it:Token request to Identity failed with status 400: invalid_grant - <description>. The description is flattened to a single line and capped at 200 characters.--verbosealways carries a reason.It also fixes two pre-existing bugs on
mainthat surfaced while testing this path. Their fixes are interleaved with the logging commits, so they are included here (with a note in each changeset) rather than split into a separate PR:AbortError.errorfield producedAbortError(undefined); it now normalizes tounknown_error.One suggestion from the internal discussion was a
Re-run with --verbosepointer in the default error text. It is deliberately left out to keep the default output unchanged; happy to add it in a follow-up if reviewers want it.How to test your changes?
packages/cli-kit, runpnpm exec vitest run src/private/node/session/exchange.test.ts src/private/node/session/device-authorization.test.ts(46 tests cover the failure paths above).SHOPIFY_APP_AUTOMATION_TOKENto an expired or revoked token and runshopify app deploy --verbose. The debug output includes theToken request to Identity failed with status 400: ...line, and the final error banner is unchanged frommain.Checklist
patchfor bug fixes ·minorfor new features ·majorfor breaking changes) and added a changeset withpnpm changeset add🤖 Generated with Claude Code