Description
We have identified an edge case in production where small but growing portion of our users are getting permanently locked out of Firebase App Check. Once a user enters this state, the SDK continuously attempts to call generateAssertion and receives DCErrorUnknownSystemFailure error from Apple and fails.
It seems like the SDK treats this as a transient error during the assertion phase so it never clears its local caches (keyid & attestationArtifact). As a result, the user is permanently stuck in this state until they manually uninstall and reinstall the app.
What we have observed
Based on our GA telemetry, here is the state of the SDK for these affected users:
- SDK has a valid
keyId (in UserDefaults) and a valid attestationArtifact (in Keychain).
- Because both exist, the SDK correctly assumes it is fully attested and calls
generateAssertion.
- Apple's framework rejects the
keyId and throws DCErrorUnknownSystemFailure.
- The SDK bubbles the error up, but does not clear the
keyId or the attestationArtifact.
- On the next app launch, the SDK reads the identical state, repeats the flow, and fails again.
Proof this is not a device migration issue
We initially suspected this was due to device migration. However, our understanding is that the attestationArtifact is stored using thisDeviceOnly in Keychain and the fact that it exists and forces the SDK into the generateAssertion flow proves that this failure is occurring on the same original physical device.
Possible missing error handling path
We noted that in PR #11986, the Firebase team had added a fallback logic to handle Apple returning DCErrorInvalidKey in the attestKey flow, which deletes the stored keyId and forces a new key to be generated.
However, for whatever reason (internal Apple daemon glitch, OS update, etc.), Apple is occasionally rejecting these existing, non-migrated keys with DCErrorUnknownSystemFailure instead of DCErrorInvalidKey during the, much later, generateAssertion phase.
Possible solution?
It may be ideal if the SDK's error handling for generateAssertion be expanded. If it returns an unrecoverable domain error like DCErrorUnknownSystemFailure, the SDK could forcefully clear the cached keyId and attestationArtifact to force a key generation just like in the attestKey phase.
This could allow the SDK to fall back to generateKey flow on the next attempt and rescue the user without requiring an app reinstall.
Reproducing the issue
Unknown. Hard to reliably reproduce.
Firebase SDK Version
12.8.0
App Check Version
11.2.0
Xcode Version
26.1.1
Installation Method
Swift Package Manager
Firebase Product(s)
App Check
Targeted Platforms
iOS
Relevant Log Output
unexpected - 操作を完了できませんでした。Failed to create a block of data that demonstrates the legitimacy of the app instance (`generateAssertion:clientDataHash:completionHandler:`); keyId.length = 44, clientDataHash = zOoeHpirGvHwLkziKasZN2inzgcL0iaDr59w1Xu5MOg=, systemVersion = 26.1; DCErrorUnknownSystemFailure - A failure has occurred, such as the failure to generate a token.
Description
We have identified an edge case in production where small but growing portion of our users are getting permanently locked out of Firebase App Check. Once a user enters this state, the SDK continuously attempts to call
generateAssertionand receivesDCErrorUnknownSystemFailureerror from Apple and fails.It seems like the SDK treats this as a transient error during the assertion phase so it never clears its local caches (
keyid&attestationArtifact). As a result, the user is permanently stuck in this state until they manually uninstall and reinstall the app.What we have observed
Based on our GA telemetry, here is the state of the SDK for these affected users:
keyId(in UserDefaults) and a validattestationArtifact(in Keychain).generateAssertion.keyIdand throwsDCErrorUnknownSystemFailure.keyIdor theattestationArtifact.Proof this is not a device migration issue
We initially suspected this was due to device migration. However, our understanding is that the
attestationArtifactis stored usingthisDeviceOnlyin Keychain and the fact that it exists and forces the SDK into thegenerateAssertionflow proves that this failure is occurring on the same original physical device.Possible missing error handling path
We noted that in PR #11986, the Firebase team had added a fallback logic to handle Apple returning
DCErrorInvalidKeyin theattestKeyflow, which deletes the storedkeyIdand forces a new key to be generated.However, for whatever reason (internal Apple daemon glitch, OS update, etc.), Apple is occasionally rejecting these existing, non-migrated keys with
DCErrorUnknownSystemFailureinstead ofDCErrorInvalidKeyduring the, much later,generateAssertionphase.Possible solution?
It may be ideal if the SDK's error handling for
generateAssertionbe expanded. If it returns an unrecoverable domain error likeDCErrorUnknownSystemFailure, the SDK could forcefully clear the cachedkeyIdandattestationArtifactto force a key generation just like in theattestKeyphase.This could allow the SDK to fall back to
generateKeyflow on the next attempt and rescue the user without requiring an app reinstall.Reproducing the issue
Unknown. Hard to reliably reproduce.
Firebase SDK Version
12.8.0
App Check Version
11.2.0
Xcode Version
26.1.1
Installation Method
Swift Package Manager
Firebase Product(s)
App Check
Targeted Platforms
iOS
Relevant Log Output