Skip to content

Fix Apple ID sign in failing with a 3840 plist parse error (notarized line) - #50

Open
Calvin-Zikakis wants to merge 2 commits into
rileytestut:notarizedfrom
Calvin-Zikakis:fix/gsa-retry-classic
Open

Fix Apple ID sign in failing with a 3840 plist parse error (notarized line)#50
Calvin-Zikakis wants to merge 2 commits into
rileytestut:notarizedfrom
Calvin-Zikakis:fix/gsa-retry-classic

Conversation

@Calvin-Zikakis

@Calvin-Zikakis Calvin-Zikakis commented Sep 4, 2026

Copy link
Copy Markdown

Same fix as #49, ported to notarized.

marketplace and notarized have diverged and neither contains the other, so #49 does not reach anyone on the classic branches. AltStore's classic (AltServer 1.8b1, AltStore 2.3b2) and classic_v2.3b1 both pin db8e0eb here, so this is the side that reaches AltServer and non EU AltStore users.

Reported in altstoreio/AltStore#1776, #1699, #1747.

What happens

Sign in makes three calls to GsService2. Apple returns an HTML error page for some of them, and sendAuthenticationRequest() hands the body straight to PropertyListSerialization with no check, so a server error surfaces as NSCocoaErrorDomain 3840 "Encountered unknown tag html on line 1" and reads like bad credentials.

o=init       HTTP 200  text/x-xml-plist  ec=0
o=complete   HTTP 200  text/x-xml-plist  ec=0
o=apptokens  HTTP 503  text/html   <html>503 Service Temporarily Unavailable ... Apple</html>

Apple's edge also pins a connection to a backend node, and once that node starts failing every later request on the same connection fails too. ALTAppleAPI uses one session for everything, so all three calls share a connection and whichever request lands after it sours is the one that dies.

Changes

Retry 5xx up to five times with backoff, each attempt on its own session so it opens a new connection. Retrying on the shared session does nothing, every attempt inherits the same dead node.

Report a failed parse as NSURLErrorBadServerResponse with the status, Content-Type and a body snippet instead of the raw 3840. ALTAppleAPI.m already does this for the other endpoints. The same helper covers the trusted device 2FA handler, which had the identical blind parse.

It parses first and only builds the better error on failure, rather than gating on the status code. A status check misses HTML served with a 200, and GSA reports its own status in the body as Status.hsc, so returning early could hide real error codes.

Numbers

25 full sign in attempts per row, on an affected Mac:

                                   old UA    new UA
one shared connection (current)      2/25     19/25
fresh connection per request         0/25     18/25
fresh connection + retry on 5xx      5/25     25/25

The User-Agent matters more than anything else here. #47 fixes that on marketplace, but there is no equivalent for this branch yet, so notarized is still on the old UA even with this merged. Worth doing both.

Testing

Verified on a Mac and iPhone that had both been failing:

  1. AltServer built from classic_v2.3b1 with this patch signed in first try and installed AltStore.
  2. AltStore 2.3b1 built with this patch, sideloaded, refreshed apps fine where stock 2.2.1 failed every time.

Builds clean for iOS.

…as a plist

Port of the marketplace-branch fix onto the notarized line, which AltStore's
classic branches pin.

Apple's GSA edge keeps a keep-alive connection pinned to a backend node. When
that node starts failing, every subsequent request on the same connection
returns 5xx and never recovers. ALTAppleAPI uses a single shared session, so
authenticate() sends init, complete and apptokens down one connection: the
first two succeed, the connection sours, and apptokens gets an HTML 503 that
surfaces as NSCocoaErrorDomain 3840 "Encountered unknown tag html on line 1".

Retry 5xx up to five times with exponential backoff, each attempt on its own
session so it opens a new connection, and route the response through a helper
that reports NSURLErrorBadServerResponse with the status, Content-Type and a
body snippet instead of an opaque parse failure.
That handler had the identical blind parse, so an HTML error page there still
surfaced as an opaque 3840. Brings the notarized-line port to parity with the
marketplace one.
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