VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Groups
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
React Native SDK
React Native quickstart
Display a paywall
Make and restore purchases
Check access
Identify users
Evaluate feature flags
Capture analytics
Groups
Track screens
Development mode
React Native SDK reference
Errors
Troubleshooting

Errors

Error codes and diagnostics of the React Native SDK, with what to do for each.

The React Native SDK reports failures as errors with a stable code, named after the operation that failed; the native iOS and Android SDK's message is kept in message.

Handle errors

Client methods never throw or reject. They resolve to a better-result Result; hooks expose the last error in error. Check isErr(), then branch on error.code. The message is for people; never match on it.

const result = await voidhash.client.purchase(monthly, { offerId: "winback_50" });

if (result.isErr()) {
  if (result.error.code === "OFFER_UNAVAILABLE") showRegularPrice();
  else reportError(result.error);
} else if (result.value.status === "completed") {
  showThankYou();
}

Cancelled, pending and deferred purchases aren't errors: they are Ok outcomes of purchase(). See Start a purchase. Network failures rarely surface as errors: reads answer from the cache and writes stay queued, reported as diagnostics.

Error types

The error class isn't exported, so compare error.code with the strings below. Two types are:

TypeUse
FlowErrorCodeUnion of the FLOW_* codes in a failed presentFlow() result.
FlowResultThe result of presentFlow(), including { status: "failed", error }.

Error codes

Configuration

CodeWhenWhat to do
FAILED_TO_INITIALIZE_VOIDHASH_CLIENTinit() failed, or the provider's initError: the binary lacks the native modules, or the native client didn't start.Rebuild the app; Expo Go isn't supported. Offer retryInit.
VOIDHASH_CLIENT_NOT_INITIALIZEDA read ran before initialization finished or after end() was called, or initialization failed. Identity, restore, sync and report calls wait on their own.Wait for useVoidhash().status === "ready".
FAILED_TO_END_VOIDHASH_CLIENTend() failed.Log it.
INVALID_ARGUMENTIn development builds, createVoidhashClient got a baseUrl or ingestUrl that isn't an absolute http(s) URL, or an unknown analyticsConsent.Fix the option. Release builds use the default and report INVALID_CONFIGURATION.
READ_ONLY_PURCHASE_NOT_ALLOWEDpurchase() or setPersonAttributesSync() ran in observer mode.Buy through your other billing SDK.
UNKNOWNA hook hit an unexpected failure.Report the full error.

Products and purchases

CodeWhenWhat to do
FAILED_TO_GET_PRODUCTSgetProducts() or useProducts() couldn't read the store.Retry, or render without store prices.
FAILED_TO_PURCHASEpurchase() failed; nothing was bought. The native code is in the message, such as PURCHASE_FAILED, or on Android ITEM_ALREADY_OWNED and STORE_UNAVAILABLE (Google Play couldn't be reached).Let the user try again. For ITEM_ALREADY_OWNED, offer to restore.
OFFER_UNAVAILABLEpurchase() with an offerId that can't be bought now. Nothing was bought.Offer the regular product.
REPLACED_SUBSCRIPTION_NOT_OWNEDAndroid. purchase() with replacing named a subscription the Google Play account doesn't own. Nothing was bought.Buy without replacing, or name the subscription the person has.
SUBSCRIPTION_REPLACEMENT_REFUSEDAndroid. Google Play refused the replacement purchase() asked for before its sheet opened; its reason is in the message. Nothing was bought.Read the message; another mode may be accepted.
INVALID_ARGUMENTpurchase() got a replacing that names no product or an unknown mode, or on Android one that isn't a different subscription. Nothing was bought.Fix the call.
FAILED_TO_RESTORE_PURCHASESrestorePurchases() couldn't reach the store, or a receipt isn't confirmed yet.Ask the user to retry. Queued receipts stay queued.
FAILED_TO_SYNC_PURCHASESsyncPurchases() couldn't read the store.Retry.
FAILED_TO_REPORT_TRANSACTIONreportTransaction() got an invalid input.Pass an App Store transaction ID or a Google Play purchase token.
FAILED_TO_SHOW_MANAGE_SUBSCRIPTIONSiosShowManageSubscriptions() couldn't open the sheet. iOS only.Link to the App Store's subscription settings instead.
FAILED_TO_PRESENT_CODE_REDEMPTION_SHEETiosPresentCodeRedemptionSheet() couldn't open the sheet. iOS only.Retry from a visible screen.

Paywalls and flows

presentFlow() resolves to { status: "failed", error } for the FLOW_* codes; it never rejects.

CodeWhenWhat to do
FLOW_NOT_ASSIGNEDNothing is assigned to the location, it doesn't exist or is archived, or the build needs a newer SDK.Show your fallback screen.
FLOW_UNAVAILABLENothing is cached for the location and Voidhash is unreachable, the download failed, or the paywall wasn't ready to show within 15 seconds.Show your fallback; retry later.
FLOW_RENDERER_MISSINGThe build doesn't include the paywall renderer.Add the renderer and rebuild.
FLOW_UNSUPPORTED_PACKAGEThe paywall was built in a format this SDK can't read.Update the SDK.
FLOW_PRESENTATION_FAILEDThere was nothing to present from, or the renderer failed.Present from a visible screen; report the error.
FLOW_DISABLEDThe client was created with enabled: false.Nothing.
FAILED_TO_GET_PAYWALL_FOR_LOCATIONgetPaywallForLocation() failed, or the paywall couldn't be read.Show your own upgrade screen.
PAYWALL_UNAVAILABLEgetPaywallForLocation() found nothing cached and Voidhash is unreachable.Hide the paywall; retry once online.

See Fall back when nothing was shown.

Identity

CodeWhenWhat to do
INVALID_ARGUMENTidentify() got a blank user ID, a person attribute was a nested object or array, or setAnalyticsConsent() got an unknown value. Nothing changed.Fix the call.
FAILED_TO_IDENTIFYidentify() or identifySync(): Voidhash refused the sign-in for good, and the previous identity was kept.Check the user ID.
FAILED_TO_SIGN_OUT, FAILED_TO_RESETsignOut() or reset() failed.Retry.
FAILED_TO_SET_GROUPgroup() failed on the device. A group type or key Voidhash can't keep is INVALID_ARGUMENT instead.Retry.
FAILED_TO_RESET_GROUPSresetGroups() failed on the device.Retry.
FAILED_TO_GET_CURRENT_PERSONgetCurrentPerson() or hasPerk() failed.Show cached state and retry.
FAILED_TO_GET_DISTINCT_IDgetDistinctId() failed.Retry after initialization.
FAILED_TO_SET_PERSON_ATTRIBUTESsetPersonAttributes() failed.Retry later. Updates already stored are sent on their own.
FAILED_TO_SET_PERSON_ATTRIBUTES_SYNCsetPersonAttributesSync() failed, or Voidhash refused the write.Retry.
FAILED_TO_RESET_PERSON_CACHEresetCache() failed.Safe to ignore.
FAILED_TO_GET_FEATURE_FLAGSgetFeatureFlags() failed.Treat flags as off.
FAILED_TO_FLUSH_ANALYTICSflush() couldn't send events now; it's the result's lastError.Nothing. Events stay queued.
FAILED_TO_SET_ANALYTICS_CONSENTThe consent applies for this run but wasn't stored.Set it again on next launch.

Network and API

CodeWhenWhat to do
AUTHENTICATION_FAILEDThe publishable key was rejected and nothing was cached. getCurrentPerson(), getFeatureFlags() and getPaywallForLocation() return it once; later reads answer from the cache.Check the key and its project. See API keys.

Other network failures don't produce errors. identifySync() and setPersonAttributesSync() report an unreachable Voidhash as { status: "deferred" }. A 401 or 403 from something in front of Voidhash, such as a proxy, a firewall or an edge page, isn't a rejected key: the SDK retries it like any temporary failure, and nothing pauses.

Diagnostics

onDiagnostic reports problems the SDK already recovered from; see Diagnostics for the handler and fields. The native SDKs' diagnostics arrive unchanged: see the Swift and Kotlin lists. The ones worth sending to your monitoring, and the ones only React Native reports:

CodeMeaning
AUTHENTICATION_FAILEDVoidhash itself rejected the publishable key. The refused traffic pauses and stays queued; fixing the key and relaunching delivers it.
CIRCUIT_OPENVoidhash failed 5 times in a row; requests are skipped and the cache is served until the next probe.
TRANSACTION_REJECTEDVoidhash refused a store receipt, for example because the store isn't set up for this app. It's sent again at the next launch, or after 6 hours.
TRANSACTION_SYNC_DEFERREDA receipt is still queued after a failed sync.
PURCHASE_FINISHED_BEFORE_SYNCAndroid only. Voidhash hadn't recorded a purchase 36 hours after payment, so the SDK acknowledged it to stop Google Play's refund.
PERSON_WRITE_REJECTEDA queued identify() or attribute update was refused for good.
ANALYTICS_EVENT_DROPPEDEvents were dropped at the 1,000-event queue limit, refused by Voidhash, or had properties that couldn't be copied; or a screen couldn't be tracked, such as one whose name isn't a string.
ANALYTICS_CONSENT_DENIEDAnalytics weren't collected because consent isn't granted.
INVALID_CONFIGURATIONA release build ignored an invalid baseUrl, ingestUrl or analyticsConsent and used the default.
HOST_CALLBACK_FAILEDA callback you passed threw, such as a usePurchase callback or screenTracking.mapScreen, or mapScreen returned a screen whose identity, name or path isn't a string. The SDK carried on without it.
BACKGROUND_TASK_FAILEDA background task, such as a refresh or a queue sync, failed outright.
LEGACY_IMPORT_SKIPPEDiOS only. Data from an earlier release wasn't carried over because it was stored for another base URL.

Next steps

  • Troubleshooting by symptom.
  • Make and restore purchases.
  • Error codes across platforms.

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousReact Native SDK referenceNextTroubleshooting

On this page

Handle errorsError typesError codesConfigurationProducts and purchasesPaywalls and flowsIdentityNetwork and APIDiagnosticsNext steps