Fix: personalize endpoint returns 500 on Apple Wallet retry#25
Open
Joseph-Cursio wants to merge 1 commit into
Open
Fix: personalize endpoint returns 500 on Apple Wallet retry#25Joseph-Cursio wants to merge 1 commit into
Joseph-Cursio wants to merge 1 commit into
Conversation
Apple's Wallet Web Service Protocol retries POST on non-2xx responses.
The personalize endpoint calls personalization.create(on:) without a
read-guard or do/catch, and PersonalizationInfo's migration declares
.unique(on: passID), so a sequential retry hits the unique constraint
and surfaces as 500 — looping Apple's retry indefinitely rather than
satisfying it.
Fix: read first, mirroring the dedup-guard pattern already used by
createRegistration (line 67-68: 'if r != nil { return .ok }').
The added regression case in 'Personalizable Pass Apple Wallet API'
issues a second POST with identical body and asserts the response is
200 OK with a single PersonalizationInfo row, not 500. Without the
fix, the test fails with 'res.status → 500 Internal Server Error'
and Vapor logs 'constraintUniqueFailed: UNIQUE constraint failed:
personalization_info.pass_id'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
personalizedPass(PassesServiceCustom+RouteCollection.swift) callspersonalization.create(on: req.db)without a read-guard ordo/catch.PersonalizationInfo's migration declares.unique(on: passID), so a sequential retry of the same/personalizePOST throws on the unique constraint and the response surfaces as500 Internal Server Error.Apple's Wallet Web Service Reference retries POST on non-2xx responses, so this turns a transient retry into a permanent failure loop. The same file already implements the symmetric pattern correctly for
createRegistration(line 67-68:if r != nil { return .ok }).Fix
Read
PersonalizationInfoTypefor the givenpassIDbefore constructing/inserting. If a row exists, skip the create and return the (deterministic) signed token directly. The token is the SHA-1 signature ofuserInfo.personalizationTokenbytes, so an identical retry produces an identical response.Test plan
Personalizable Pass Apple Wallet APItest inTests/VaporWalletPassesTests. After the first successful POST + assertions, issues a second POST with identical body and asserts:res.status == .ok(not.internalServerError)res.body.readableBytes > 0(signed token still returned)PersonalizationInfo.query(on: app.db).all().count == 1(no duplicate row)useEncryptedKey: [true, false], so coverage applies to both code paths.Expectation failed: (res.status → 500 Internal Server Error) == (.ok → 200 OK)on both parameterized cases. The Vapor warning log includesconstraintUniqueFailed: UNIQUE constraint failed: personalization_info.pass_id, matching the diagnosis.Notes
This was surfaced by a SwiftIdempotency road-test against this package — full findings under docs/wallet-package-trial/. The road-test was measurement-only (annotation surface, no logic edits); this PR is the separate upstream fix it identified.