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 |
|
Amazing thank you much! I've merged this with some minor changes, will release an update ASAP with this fix 🙂 |
Apple's edge serves at most two requests per connection and 503s everything after that. Signing in takes three requests over one pooled session, so apptokens always fails and the HTML 503 gets parsed as a plist, which is where the 3840 comes from. Same fix as rileytestut#52, which landed on notarized. This branch still has the bug.
GSA seems to, sometimes, reject HTTP requests made on a kept-alive connection with a 503. This was either the real root cause, or a second root cause, for #243. Fix this by creating a new HTTP connection for each GSA request. See also: rileytestut/AltSign#52 and rileytestut/AltSign#47 Speculatively fixes #232
|
Great to hear a release is coming. One thing worth checking before you cut it, since it may affect whether the release actually resolves this for people: This bug looks like it has two independent triggers, and #52 addresses one of them. The other is the stale What's been measured so far, and what hasn't:
So I can't tell you whether #52 alone is sufficient — it might well be, if connection pinning is the dominant factor. But it's the one combination without data behind it, and it's the one about to go out. If #51 is uncontroversial, shipping both together would remove the question entirely. Happy to test stale-UA-plus-fresh-connection on my setup and report back if that's useful — I have the instrumentation still in place and can isolate the variable. Just say the word and I'll post the result here. Also flagging, in case it's not on your radar: 1.7.5 (published yesterday) still carries the stale UA in both architecture slices of |
Apple's edge in front of gsa.apple.com began (~2026-08-31) serving only a couple of requests per TLS connection and 503ing the rest. isideload reused one pooled connection for the 3 login requests, so later ones failed. Set pool_max_idle_per_host(0) so each request opens a fresh connection. Mirrors rileytestut/AltSign#52. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.