Skip to content

[App Check] iOS SDK permanently traps users in generateAssertion loop when it returns DCErrorUnknownSystemFailure #16256

Description

@amadrian

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.

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions