You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Empirical findings from a one-off mistdemo probe-duplicate-subscription
run against a real CloudKit container (public DB) confirm that
CloudKit Web Services enforces subscription uniqueness on the (recordType, firesOn) tuple, not on subscriptionID.
This matters because the failure surfaces as the generic INTERNAL_ERROR with the misleading reason "could not find subscription we just created", with no formal CONFLICT/EXISTS code — exactly the case #379 added per-item
surfacing for, but the misleading reason text doesn't tell the caller why the duplicate fires.
MistKit now surfaces this via:
SubscriptionOperationFailure.isLikelyDuplicate: Bool — opt-in
hint, exact-match on the reason string.
CloudKitError.subscriptionLikelyDuplicate(SubscriptionOperationFailure)
— thrown from the createSubscription convenience wrapper when the
hint matches. Batch modifySubscriptions is unchanged; raw failures
still flow through SubscriptionResult.failure.
Both are intentionally hedged (isLikely…, "likely cause: …") because
the wire-level code is just INTERNAL_ERROR — the duplicate
interpretation is MistKit's inference from the reason string.
Probe matrix (2026-05-25, public DB)
Seed creates one subscription, then the probe creates a second with
one or more axes varied:
different ID, same recordType, different firesOn ([.create] vs [.update])
SUCCESS
4
different ID, same recordType, supersetfiresOn ([.create] vs [.create, .update])
SUCCESS — uniqueness is exact-set match, not overlap
5
different ID, different recordType (Note → Article)
404 (Article absent from public schema — not a clean control)
Surprises
Same subscriptionID twice succeeds silently (Fix "method_lines" issue in Sources/MistKit/MKDatabase.swift #2). The
intuitive "IDs must be unique on create" mental model is wrong —
CloudKit is idempotent on the ID and quietly returns the existing
record.
Uniqueness on firesOn is exact-set match, not overlap (Support ARM in GitHub Actions #4).
Two subscriptions with disjoint or partly-overlapping fire-event
sets coexist; only an identical set collides.
Reproduction
cd Examples/MistDemo
swift run mistdemo probe-duplicate-subscription \
--database public --verbose
The command seeds a subscription, probes with five variations,
cleans up after itself, and prints serverErrorCode + raw reason
for each probe. It is not part of test-public/test-private;
run it manually when investigating subscription failures.
Suggested follow-ups
Apple Feedback Assistant report: ask Apple to either
(a) add a SUBSCRIPTION_EXISTS / CONFLICT server error code for
this case, or (b) document the (recordType, firesOn) uniqueness
constraint and the misleading INTERNAL_ERROR reason in
CloudKit Web Services docs.
Revisit the exact-match detection in isLikelyDuplicate if the
probe surfaces wording variants in future runs.
Consider documenting client-side cleanup pattern: clean by (recordType, firesOn) identity via listSubscriptions, not by subscriptionID alone (an old subscription under a different ID
can still collide).
Summary
Empirical findings from a one-off
mistdemo probe-duplicate-subscriptionrun against a real CloudKit container (public DB) confirm that
CloudKit Web Services enforces subscription uniqueness on the
(recordType, firesOn)tuple, not onsubscriptionID.This matters because the failure surfaces as the generic
INTERNAL_ERRORwith the misleading reason"could not find subscription we just created", with no formalCONFLICT/EXISTScode — exactly the case #379 added per-itemsurfacing for, but the misleading reason text doesn't tell the caller
why the duplicate fires.
MistKit now surfaces this via:
SubscriptionOperationFailure.isLikelyDuplicate: Bool— opt-inhint, exact-match on the reason string.
CloudKitError.subscriptionLikelyDuplicate(SubscriptionOperationFailure)— thrown from the
createSubscriptionconvenience wrapper when thehint matches. Batch
modifySubscriptionsis unchanged; raw failuresstill flow through
SubscriptionResult.failure.Both are intentionally hedged (
isLikely…, "likely cause: …") becausethe wire-level code is just
INTERNAL_ERROR— the duplicateinterpretation is MistKit's inference from the reason string.
Probe matrix (2026-05-25, public DB)
Seed creates one subscription, then the probe creates a second with
one or more axes varied:
recordType, samefiresOnisLikelyDuplicate=truerecordType, samefiresOnrecordType, differentfiresOn([.create]vs[.update])recordType, supersetfiresOn([.create]vs[.create, .update])recordType(Note→Article)Articleabsent from public schema — not a clean control)Surprises
subscriptionIDtwice succeeds silently (Fix "method_lines" issue in Sources/MistKit/MKDatabase.swift #2). Theintuitive "IDs must be unique on create" mental model is wrong —
CloudKit is idempotent on the ID and quietly returns the existing
record.
firesOnis exact-set match, not overlap (Support ARM in GitHub Actions #4).Two subscriptions with disjoint or partly-overlapping fire-event
sets coexist; only an identical set collides.
Reproduction
cd Examples/MistDemo swift run mistdemo probe-duplicate-subscription \ --database public --verboseThe command seeds a subscription, probes with five variations,
cleans up after itself, and prints
serverErrorCode+ rawreasonfor each probe. It is not part of
test-public/test-private;run it manually when investigating subscription failures.
Suggested follow-ups
(a) add a
SUBSCRIPTION_EXISTS/CONFLICTserver error code forthis case, or (b) document the
(recordType, firesOn)uniquenessconstraint and the misleading
INTERNAL_ERRORreason inCloudKit Web Services docs.
isLikelyDuplicateif theprobe surfaces wording variants in future runs.
(recordType, firesOn)identity vialistSubscriptions, not bysubscriptionIDalone (an old subscription under a different IDcan still collide).
References