Skip to content

Fix cryptic decoding error when Apple rejects credentials (e.g. locked account) - #7

Open
zakis5 wants to merge 1 commit into
XcodesOrg:mainfrom
zakis5:fix/account-locked-decoding-error
Open

zakis5 wants to merge 1 commit into
XcodesOrg:mainfrom
zakis5:fix/account-locked-decoding-error

Conversation

@zakis5

@zakis5 zakis5 commented Sep 22, 2026

Copy link
Copy Markdown

Why

When trying to install a different version of xcode from xcodes CLI, i got this error:

➜  code $ sudo xcodes install 26.5
Apple ID: zakishaheen@me.com
Apple ID Password:
The operation couldn’t be completed. (DecodingError.DecodingError.dataCorrupted: Data was corrupted. Debug description: The given data was not valid JSON.. Underlying error: Error Domain=NSCocoaErrorDomain Code=3840 "Unexpected character '<' around line 1, column 1." UserInfo={NSJSONSerializationErrorIndex=0, NSDebugDescription=Unexpected character '<' around line 1, column 1.})
The operation couldn’t be completed. (DecodingError.DecodingError.dataCorrupted: Data was corrupted. Debug description: The given data was not valid JSON.. Underlying error: Error Domain=NSCocoaErrorDomain Code=3840 "Unexpected character '<' around line 1, column 1." UserInfo={NSJSONSerializationErrorIndex=0, NSDebugDescription=Unexpected character '<' around line 1, column 1.})

Summary

  • srpLogin decoded the sign-in response body as SignInResponse before checking the HTTP status code. When Apple rejects credentials (e.g. a locked account) it can return an HTML error page instead of JSON, so decoding threw NetworkError.decoding with Foundation's raw DecodingError text instead of a readable error. This is what xcodes install users see as:

    The operation couldn't be completed. (DecodingError.DecodingError.dataCorrupted: ... Unexpected character '<' around line 1, column 1. ...)
    
  • Decoding is now best-effort; the HTTP status code drives branching regardless of whether the body parsed as JSON, and a truncated preview of the raw body is used as the error message when it doesn't parse.

Test plan

  • Added testSrpLoginThrowsAccountLockedWhenAppleRejectsCredentialsWithJSON — baseline case, JSON error body still maps to AuthenticationError.accountLocked.
  • Added testSrpLoginThrowsDescriptiveAccountLockedErrorWhenAppleRejectsCredentialsWithHTML — reproduces the reported bug (403 + HTML body) and asserts a readable accountLocked error instead of a raw DecodingError.
  • swift test passes (35/35, 1 skipped live-network test).
  • Built the xcodes CLI (XcodesOrg/xcodes) against this branch locally and ran xcodes update to confirm the real login flow still works end-to-end.

Apple can respond to /appleauth/auth/signin/complete with an HTML
error page instead of JSON when it rejects credentials (e.g. a
locked account). srpLogin unconditionally decoded the body as
SignInResponse before looking at the HTTP status code, so a non-JSON
body threw NetworkError.decoding with Foundation's raw DecodingError
text ("Unexpected character '<' around line 1, column 1.") instead of
a readable AuthenticationError.

Decode is now best-effort, and the HTTP status code drives branching
regardless of whether the body parsed. When it doesn't parse, a
truncated preview of the raw body is used as the error message
instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@zakis5
zakis5 marked this pull request as ready for review September 22, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant