Use a separate connection for each GrandSlam request - #52
Conversation
Apple's edge began serving at most two requests per connection around 2026-08-31, answering everything after that with a 503 HTML error page. Authenticating takes three requests -- init, complete, and apptokens -- and URLSession sends them over one pooled connection, so apptokens was rejected every time and signing in always failed at the last step. Give each request its own session, and therefore its own connection. Verified by replaying a captured request: identical bytes succeed on a fresh connection and return 503 as the third request on a reused one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WrnGBkYZDRb57McNgLxCaE
The response body is parsed as a property list before the status code is checked, so an HTML error page from Apple surfaces as NSCocoaErrorDomain 3840, "The data couldn't be read because it isn't in the correct format." That describes the parser rather than the failure, and sends users looking at their Apple ID, their anisette server, and their OS version. Check for a 5xx first and report it as what it is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WrnGBkYZDRb57McNgLxCaE
|
Measured the per-connection allowance more precisely, comparing this PR's approach against the User-Agent change proposed in #47 ( 6 requests down one connection, 3 trials each: So #47/#51 does raise the allowance, but the current string sometimes allows only one request, not two. 20 requests each on their own fresh connection, current string: 20/20 200, no failures. I could not reproduce the ~20-25% fresh-connection failure rate cited in #51; it may be IP or account specific. That is why this PR uses a connection per request rather than raising the allowance: it holds whatever Apple sets the limit to, and needs no User-Agent change. |
|
Independent confirmation of both the diagnosis and the fix, from a separate machine, network and Apple ID. Reproduced the connection allowance with an intentionally invalid account name ( Applied the same change — one One data point worth adding for the AltStore side: the identical hook is needed inside Also worth separating out: the stale |
Signing in has been failing since roughly 2026-08-31 with
NSCocoaErrorDomain 3840, "The data couldn't be read because it isn't in the correct format."Cause
Apple's edge in front of
gsa.apple.comnow serves at most two requests per connection and answers everything after that with a 503 HTML error page.Authenticating takes three requests, and
URLSessionsends them over one pooled connection:The password is accepted; only the token exchange fails. The 503's HTML body is then parsed as a property list, which is where the 3840 error comes from — the message describes the parser, not the failure.
The 503 is generated at the edge rather than by GrandSlam: successful responses carry
Content-Type: text/x-xml-plistandX-Apple-I-Retry-Request-UUID, while the 503 hasContent-Type: text/htmland neither.Reproducing
Any POST body works, valid or not — only the position in the connection matters:
The same request on a fresh connection returns 200. Retrying does not help, because the retry reuses the same pooled connection.
Changes
apptokensarrives first on a fresh connection.Verified end to end against a real Apple ID:
init→complete→apptokensall return 200, and sign-in and refresh work again on both AltServer and on-device AltStore.This looks like the cause behind the recent reports in altstoreio/AltStore#1776, #1777, #1781, #1782 and SideStore/SideStore#1459, #1464, #1465, which are all the same 3840 error.
Targeting
notarizedsince that is what AltStore Classic pins;marketplacecompiles the SRP paths out.