Skip to content

Certificate Wizard: show the real signing error instead of a blanket HTTP 502 - #5567

Merged
shai-almog merged 3 commits into
masterfrom
fix/certwizard-apple-error-messages
Aug 19, 2026
Merged

Certificate Wizard: show the real signing error instead of a blanket HTTP 502#5567
shai-almog merged 3 commits into
masterfrom
fix/certwizard-apple-error-messages

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

A customer reported that for 24 hours, clicking Sync with Apple returned:

Codename One cloud signing service failed (HTTP 502). Try again later.

Their App Store Connect key was fine. So was the sync — it had already succeeded.

What was happening

Production logs show Apple answering one call with a 404:

GET /v1/appGroups?limit=200 status=404 code=NOT_FOUND
detail=The path provided does not match a defined resource type.

That is Apple saying the path is not a resource type it knows — App Store Connect does not offer App Groups to that account. (A collection that exists but is empty answers 200 with an empty data array.)

CloudSigningService.refresh() chains seven calls and loads App Groups last, and any failure there discarded the six that had already succeeded. afterMutation calls reload() on success, so the reconcile completed, the follow-up refresh died on call seven, and the developer was told to wait out something that had worked.

Two things then made it unreadable: the cloud service reported every Apple failure as 502, and CloudSigningService.message() short-circuited on code >= 500 and threw the response body away.

Changes

8635e0f09a — surface what the service actually said. The generated REST client already hands the callback the raw body on an error status (via the onErrorCodeString handler it emits), so the explanation was there all along. SigningError now reads it for every status and classifies the failure; the banner renders it with a next step attached — "Open ASC API Key" for a credential problem, "Try again" for something genuinely transient.

Bodies are not trusted blindly: a proxy or CDN in front of the service answers 5xx with its own HTML page or a stub like error code: 522, so a 5xx body has to read like prose before it reaches the UI. The banner became a SpanLabel because a Label clipped these messages to one line, and it stays selectable so the text can be pasted into a support thread.

7e432be24d — stop one optional call from discarding the account. By the time App Groups load, the six calls before them have proved both the Codename One login and the Apple key are good, so a failure there is treated as "no App Groups". The developer keeps their certificates, bundle IDs, devices, profiles and APNs keys on screen.

Specs track the server contract: NotConfigured becomes AscKeyProblem, and the Apple-calling paths document 422/429/404 alongside 502. openapi.json is regenerated from the yaml it is derived from.

Tests

38/38 green (mvn -B test), including:

  • SigningErrorTest — the status→message mapping, including the CDN-stub and HTML-error-page cases that must never reach the UI.
  • CertificateWizardErrorBannerTest — drives the real Sync with Apple button and asserts what lands on screen, that the old catch-all string is gone, and that the credential action navigates to the ASC API Key page.

Related

Server side is BuildCloud #130, which fixes the root cause (listAppGroups reads the 404 as "no App Groups") and stops flattening every Apple failure into a 502. Either side alone clears the customer's symptom: the server fix reaches everyone on a released wizard without a client update, and this one fixes a rebuilt wizard without waiting for a deploy.

🤖 Generated with Claude Code

shai-almog and others added 2 commits August 19, 2026 07:56
"Sync with Apple" reported every server-side failure as "Codename One cloud
signing service failed (HTTP 502). Try again later." CloudSigningService.message()
short-circuited on `code >= 500` and threw the response body away -- so when the
cloud service explained that the account's App Store Connect API key had been
revoked, the developer was told to wait it out instead.

The generated REST client already hands the callback the raw body on an error
status (the onErrorCodeString handler it emits), so the body was there the whole
time. SigningError now reads it for every status and classifies the failure, and
the banner renders what the service said.

Bodies are not trusted blindly: a proxy or CDN in front of the service answers
5xx with its own HTML page or a stub like `error code: 522`, so a 5xx body has to
look like prose before it reaches the UI, and anything HTML-ish, JSON-ish or
overlong falls back to a written message.

The banner grew a next step to go with the sentence -- "Open ASC API Key" for a
credential problem, "Try again" for something genuinely transient -- and became a
SpanLabel, because a Label clipped these messages to one line. It stays
selectable so the text can be copied into a support thread.

Specs track the server: NotConfigured becomes AscKeyProblem, and the Apple-calling
paths document 422/429/404 alongside 502. openapi.json is regenerated from the
yaml.

Tests: SigningErrorTest pins the mapping (including the CDN and HTML cases);
CertificateWizardErrorBannerTest drives the real "Sync with Apple" button and
asserts what lands on screen and where the buttons go.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
App Groups load as the last of the seven calls a refresh chains together, and
any failure there discarded the six that had already succeeded and reported an
error instead. Apple answers `GET /v1/appGroups` with 404 "The path provided
does not match a defined resource type" for accounts it does not offer the
resource to, so those developers got an error on every refresh -- and because a
successful "Sync with Apple" ends in a refresh, a sync that had worked
perfectly reported "cloud signing service failed (HTTP 502). Try again later."

By the time this call runs, the six before it have proved both the Codename One
login and the Apple key are good, so treating a failure here as "no App Groups"
gives up nothing: the developer keeps their certificates, bundle IDs, devices,
profiles and APNs keys on screen. The server no longer raises this at all, but
the wizard should not have been this brittle either -- and a released wizard
gets the fix without waiting for a deploy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

check-copyright-headers validates every file a PR adds *or modifies*, and the
three files in certificatewizard/api had no header: SigningError.java is new and
I wrote it without one, while CloudSigningService.java and SigningService.java
predate this branch and were only caught because these changes touch them.

Header copied verbatim from CertificateWizard.java in the same module.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shai-almog
shai-almog merged commit dc9aa2b into master Aug 19, 2026
10 checks passed
@shai-almog
shai-almog deleted the fix/certwizard-apple-error-messages branch August 19, 2026 12:32
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