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.
izaankml added a commit to izaankml/AltSign that referenced this pull request Sep 5, 2026
Since early September 2026 GrandSlam intermittently answers the sign-in
requests with an HTML 503 page instead of a plist, which AltSign fed
straight to PropertyListSerialization and surfaced as the opaque
"Encountered unknown tag html on line 1" (NSCocoaError 3840).

Two changes fix it:

- Send the modern AuthKit User-Agent. Apple now rejects the obsolete
  akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0 string a large fraction of the
  time; the AuthKit string current akd sends is accepted (measured on an
  affected Mac: old string 503'd 12/100, AuthKit 0/100).

- Use a fresh ephemeral URLSession per request and retry. GrandSlam's
  edge assigns a keep-alive connection to one backend node; once that
  node starts failing, every later request on the same connection 503s
  and does not recover. Sign-in sends init, complete and apptokens over
  one shared session, so the third request always failed. A new
  connection per attempt, plus a bounded 5xx retry (up to 5 attempts,
  1/2/4/8s backoff, within the ~30s anisette window), resolves it.

Root cause and approach from altstoreio/AltStore#1776 (Calvin-Zikakis)
and the upstream fixes in rileytestut#47/rileytestut#50/rileytestut#51.
izaankml added a commit to izaankml/AltSign that referenced this pull request Sep 5, 2026
Since early September 2026 GrandSlam intermittently answers the sign-in
requests with an HTML 503 page instead of a plist, which AltSign fed
straight to PropertyListSerialization and surfaced as the opaque
"Encountered unknown tag html on line 1" (NSCocoaError 3840).

Two changes fix it:

- Send the modern AuthKit User-Agent. Apple now rejects the obsolete
  akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0 string a large fraction of the
  time; the AuthKit string current akd sends is accepted (measured on an
  affected Mac: old string 503'd 12/100, AuthKit 0/100).

- Use a fresh ephemeral URLSession per request and retry. GrandSlam's
  edge assigns a keep-alive connection to one backend node; once that
  node starts failing, every later request on the same connection 503s
  and does not recover. Sign-in sends init, complete and apptokens over
  one shared session, so the third request always failed. A new
  connection per attempt, plus a bounded 5xx retry (up to 5 attempts,
  1/2/4/8s backoff, within the ~30s anisette window), resolves it.

Root cause and approach from altstoreio/AltStore#1776 (Calvin-Zikakis)
and the upstream fixes in rileytestut#47/rileytestut#50/rileytestut#51.
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