In iOS app development, errors are more common than one would like. The “SKErrorDomain Error 0” is among the most unpleasant: it doesn’t break the app completely, but messes with the in-app purchases and subscriptions, leaving you without the potential profits.
In this guide, we discuss what can cause the error, how to possibly solve it, and prevent it from recurring. For both seasoned developers and beginners, this article is your comprehensive guide to understanding and handling the SKErrorDomain Error 0.
Important Update (iOS 18): Apple deprecated all StoreKit 1 APIs at WWDC 2024. While your existing apps continue to work, migrating to StoreKit 2 is now strongly recommended. StoreKit 2 handles unknown errors differently — see the “StoreKit 2 Considerations” section below.
What Is SKErrorDomain Error 0?
SKErrorDomain Error 0, also known as SKError.Code.unknown, is a catch-all error that occurs when StoreKit encounters an unspecified failure. Unlike other error codes that point to specific issues (like payment cancellation or invalid product identifiers), Error 0 simply indicates that something went wrong without providing clear details.
This makes it particularly frustrating to debug, as the root cause could be anything from Apple’s servers being temporarily unavailable to configuration issues in your app.
The Causes of SKErrorDomain Error 0
A common culprit is network-related issues: intermittent connectivity or weak signals can trigger this error. In most cases, however, the response is too slow from Apple’s side.
Another go-to reason is the errors in the StoreKit configuration, like an incorrect setup of in-app purchases or issues with the sandbox testing environment. Let’s take a closer look.
Network Issues
Unstable or weak internet connections can interfere with the smooth operation of StoreKit transactions and cause disruptions when an app tries to communicate with Apple’s servers for in-app purchases or subscriptions. For instance, if the device loses internet connection during a transaction, or if the connection isn’t strong enough to facilitate data exchange, the system may throw a SKErrorDomain Error 0. Run the app on several devices and networks to rule out this possibility, and check out Apple’s System Status.
Pro tip: Third-party services like RevenueCat and Adapty process billions of requests and often detect Apple API issues before Apple’s official status page updates. Consider monitoring multiple status pages during outages.

StoreKit Configuration Issues
StoreKit is Apple’s framework for handling in-app purchases and subscriptions, and if not set up correctly, it can cause several issues. A common mistake is an incorrect setup of in-app purchases: the product identifiers in your code don’t match those set up in App Store Connect.
Another potential pitfall lies within the sandbox testing environment. If the testing account isn’t properly set up or if there’s a mismatch between the environment and the app settings, this can also result in an error.
Issues with receipt validation or handling transaction states can also lead to errors. Careful and correct configuration of StoreKit is crucial to prevent the SKErrorDomain Error 0 and ensure seamless in-app transactions.
Apple Server-Side Issues
Error 0 frequently originates from Apple’s backend systems rather than your code. The sandbox environment is particularly prone to instability. If your app was working fine and suddenly started throwing Error 0, check Apple’s system status and wait — the issue often resolves itself within hours.
Ask to Buy and Strong Customer Authentication (SCA)
Two less obvious causes of Error 0:
- Ask to Buy: When a child in a Family Sharing group attempts a purchase, the transaction is interrupted pending parental approval. This can manifest as Error 0.
- Strong Customer Authentication (SCA): In the European Economic Area, payments require additional verification. If this process is interrupted, you may see Error 0.
Getting More Details from Error 0
The SKError object often contains an NSUnderlyingError with more specific information. Always check this property when debugging:
swift
if let skError = error as? SKError, skError.code == .unknown {
if let underlyingError = skError.userInfo[NSUnderlyingErrorKey] as? NSError {
// Check nested errors for actual cause
if let innerError = underlyingError.userInfo[NSUnderlyingErrorKey] as? NSError {
print("Root cause: \(innerError.localizedFailureReason ?? "Unknown")")
}
}
}Common underlying error patterns:
| Domain | Code | Meaning |
|---|---|---|
| ASDErrorDomain | 504 | Server timeout |
| AMSErrorDomain | 305 | Verification required (payment method issue) |
| NSURLErrorDomain | -1001 | Request timeout |
| NSURLErrorDomain | -1003 | Cannot find host |
Troubleshooting SKErrorDomain Error 0
Troubleshooting the error involves methodically addressing its potential causes:
Check network connectivity. Ensure that the device has a stable and strong internet connection: if possible, test on several devices and networks.
Review StoreKit configuration. Verify the product identifiers in your code match those set up in App Store Connect. Make sure your in-app purchases are correctly configured.
Check App Store Connect agreements. Expired or unsigned agreements (Paid Applications Agreement, tax forms) can cause API calls to fail with Error 0.
Check receipts validation and transaction states. Both the validation process and transaction states should be handled correctly.
Test in sandbox environment. Confirm that your sandbox testing account is properly set up and there’s no mismatch between the environment and app settings. Test your in-app purchases in this environment to check if they are working as expected.
Speaking of which, these are the steps you should follow in both Sandbox and Production environments.
SKErrorDomain Error 0 in Sandbox and Production
Verify your sandbox account. Ensure that your sandbox tester account is correctly set up in App Store Connect. Sign out of any real Apple ID accounts in your device settings and then, from within the app, attempt an in-app purchase. You’ll be prompted to sign in, and you should use your sandbox account credentials.
Check product identifiers. They should match those in your code. An inconsistency here can cause the SKErrorDomain Error 0.
Review transaction states. Make sure your code handles all possible transaction states, including purchased, failed, restored, and deferred. Incorrect handling of these states can lead to errors.
Don’t mix sandbox and production. Receipt validation can fail if it’s checking against the production server while testing in the sandbox environment. The validation should occur against the sandbox server when testing, and against production in real-life.
Reset test environment. If you’re still encountering issues, try resetting your test environment. This can include deleting and reinstalling the app, signing out of the sandbox account, and then repeating the testing process.
Create a new sandbox account. Sandbox accounts can enter a “bad state” that’s impossible to fix. Rather than troubleshooting a broken account, simply create a new sandbox tester in App Store Connect.
Use StoreKit Configuration files. For local testing in Xcode (iOS 14+), StoreKit Configuration files let you test without network calls or App Store Connect. If your purchases work with a config file but fail in sandbox, the issue is likely with your App Store Connect configuration or sandbox account — not your code.
Consult Apple’s documentation. Apple provides extensive documentation for StoreKit. Refer to it if you’re unsure about any configurations or processes.
By following these steps, you can mitigate and potentially resolve the SKErrorDomain Error 0 in the production environment, ensuring a seamless experience for the end users. If the problem persists, consider reaching out to Apple’s developer support: they can provide further assistance and possibly identify any hidden issues. Here’s how to file a bug report.

Submitting a Bug Report to Apple
- Open the Feedback Assistant page or the Feedback Assistant app on your Mac.
- Log in with your Apple ID associated with your Developer Program membership.
- Click on the “New Feedback” button.
- In the form that appears, provide as much detailed information as you can about the issue. Include the specific error (in this case, SKErrorDomain Error 0), the environment (sandbox or production), steps to reproduce the error, expected and actual results, and any relevant code snippets or logs.
- Attach any necessary files, like screenshots or screen recordings, that can further illustrate the issue.
- Review your report for completeness and accuracy, then click “Submit”.
Apple will investigate your report and, in many cases, will respond with further information or potential solutions. This can take up to several days, but the answer is usually worth it.

StoreKit 2 Considerations
With StoreKit 1 deprecated in iOS 18, understanding how StoreKit 2 handles unknown errors is increasingly important.
How StoreKit 2 Handles Unknown Errors
StoreKit 2 uses Swift enums instead of numeric error codes. The equivalent of Error 0 is StoreKitError.unknown. However, there’s a key difference: user cancellation is no longer an error — it’s a separate case in PurchaseResult.
swift
func purchase(_ product: Product) async {
do {
let result = try await product.purchase()
switch result {
case .success(let verification):
// Handle successful purchase
break
case .userCancelled:
// User cancelled — NOT an error, don't show error message
break
case .pending:
// Ask to Buy or other pending state
break
@unknown default:
break
}
} catch StoreKitError.unknown {
// Equivalent to SKErrorDomain Error 0
// Apply same troubleshooting: check network, server status, configuration
} catch {
// Handle other errors
}
}iOS 18.2+ Important Change
Starting with iOS 18.2, a common cause of unknown errors in UIKit apps is the new requirement to specify UI context for purchases:
swift
// iOS 18.2+ requires confirmIn parameter for UIKit apps
if #available(iOS 18.2, *) {
result = try await product.purchase(confirmIn: viewController)
} else {
result = try await product.purchase()
}Without this change, purchases may fail with unknown errors on iOS 18.2 and later. SwiftUI apps using StoreKit views are generally unaffected.
Preventing SKErrorDomain Error 0
Understanding how to prevent errors is as important as knowing how to fix them. Let’s explore the proactive strategies to keep SKErrorDomain Error 0 at bay.
Configure StoreKit Properly
StoreKit configuration is the bedrock of in-app purchases and subscriptions in iOS applications, and its correct setup is instrumental in preventing the SKErrorDomain Error 0. Ensuring that product identifiers match your code and App Store Connect is a fundamental starting point. Misalignments here can trigger the error, disrupting the app’s operation.
Equally important is the accurate handling of transaction states. Your code should account for all possible states, such as purchased, failed, restored, and deferred. Neglecting any of these can invite unwanted errors.
Setting up the sandbox testing environment correctly is vital. This includes having a properly configured testing account and ensuring that the environment settings align with the app settings.
By giving due attention to these StoreKit configurations, you can significantly reduce the risk of encountering the SKErrorDomain Error 0, resulting in a smoother development process and a more reliable app for your users.
Implement Retry Logic
Since Error 0 often stems from transient server issues, implementing retry logic can recover many failed purchases:
swift
func purchaseWithRetry(_ product: SKProduct, maxAttempts: Int = 3) async throws {
var lastError: Error?
for attempt in 1...maxAttempts {
do {
try await makePurchase(product)
return // Success
} catch let error as SKError where error.code == .unknown {
lastError = error
// Exponential backoff: 2s, 4s, 8s
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(attempt))) * 1_000_000_000)
}
}
throw lastError ?? SKError(.unknown)
}Important: Never retry immediately — rapid retries can trigger rate limiting and make the problem worse.
Utilize Debugging Tools Effectively
Xcode’s debugger provides valuable insights into your code’s execution, allowing you to catch any misconfigurations in real-time. Regularly stepping through your code, especially the parts handling StoreKit transactions, can help ensure that all processes are functioning as expected.
Additionally, Xcode’s console can display useful logs during a transaction, aiding in identifying any potential issues.
Use StoreKit Configuration files for testing. They let you simulate various error scenarios:
- Enable “Fail Transactions” to test your error handling
- Configure “Ask to Buy” for pending transaction states
- Use “Interrupted Purchases” for partial transactions
- The Transaction Manager lets you approve/decline transactions manually
By consistently applying these debugging techniques, you can spot and rectify potential issues early, reducing the likelihood of encountering the SKErrorDomain Error 0.
Conclusion: It Pays to Debug
If you’re reading this article, you’ve probably tried all the steps above and were looking for a more specific solution. But the thing is, most of the errors are human, and sometimes a single missed (or extra) comma can ruin the process. No guide can stop you from making mistakes, but simplifying and automating the process as much as possible might help minimize the range of human errors.
With StoreKit 1 now deprecated, consider migrating to StoreKit 2 for cleaner error handling, automatic transaction verification, and long-term support. The investment in migration pays off through more maintainable code and better debugging capabilities.
FAQ
SKError.Code.unknown, is a catch-all error that iOS developers encounter when StoreKit fails for an unspecified reason. It indicates something went wrong during an in-app purchase, but doesn’t specify the exact cause. In StoreKit 2, the equivalent is StoreKitError.unknown. NSUnderlyingError property of the SKError object. It often contains nested errors with more specific information, including domain-specific error codes (like ASDErrorDomain or AMSErrorDomain) and localized failure reasons that reveal the actual cause. SKError.unknown in your transaction observer. For new projects, use StoreKit 2 which provides cleaner error handling and is actively maintained by Apple. 



