{"record":{"id":"8fd1ee96f0d653a2","repo":"microg/GmsCore","slug":"failed-to-retrieve-client-information","errorCode":null,"errorMessage":"Failed to retrieve client information.","messagePattern":"Failed to retrieve client information\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt","lineNumber":173,"sourceCode":"                ).requestAuthProofToken(password)\n            }\n            return runBlocking { deferred.await() }\n        }\n\n        private fun createIAPCore(context: Context, account: Account, pkgName: String): IAPCore {\n            val key = \"$pkgName:${account.name}\"\n            val cacheEntry = iapCoreCacheMap[key]\n            if (cacheEntry != null) {\n                if (cacheEntry.expiredAt > System.currentTimeMillis())\n                    return cacheEntry.iapCore\n                iapCoreCacheMap.remove(key)\n            }\n            val authData = AuthManager.getAuthData(context, account)\n                ?: throw RuntimeException(\"Failed to obtain login token.\")\n            val deviceEnvInfo = createDeviceEnvInfo(context)\n                ?: throw RuntimeException(\"Failed to retrieve device information.\")\n            val clientInfo = createClient(context, pkgName)\n                ?: throw RuntimeException(\"Failed to retrieve client information.\")\n            val iapCore = IAPCore(context.applicationContext, deviceEnvInfo, clientInfo, authData)\n            iapCoreCacheMap[key] =\n                IAPCoreCacheEntry(iapCore, System.currentTimeMillis() + EXPIRE_MS)\n            return iapCore\n        }\n    }\n\n    private fun getPreferredAccount(extraParams: Bundle?): Account {\n        val name = extraParams?.getString(\"accountName\")\n        name?.let {\n            extraParams.remove(\"accountName\")\n        }\n        return getGoogleAccount(context, name)\n            ?: throw RuntimeException(\"No Google account found.\")\n    }\n\n    private fun isBillingSupported(\n        apiVersion: Int,","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt#L155-L191","documentation":"createIAPCore calls createClient(context, pkgName) to build the client-info object for the calling package; null triggers this RuntimeException. It means the caller's package information could not be resolved, so a valid IAP client cannot be created.","triggerScenarios":"Any billing call through createIAPCore with a pkgName whose PackageInfo/signature can't be resolved — e.g. the calling package is not installed, is untracked, or package-manager lookups fail.","commonSituations":"Caller package name typo/not passed in extras; calling app uninstalled or a shadow/instant install; microG lacks signature/package data for the caller; package manager restrictions on some ROMs.","solutions":["Ensure the calling app is installed and passes its correct package name through the billing extras.","Verify the app is visible to the service (package visibility / QUERY_ALL_PACKAGES or explicit queries on Android 11+).","Reinstall the calling app so signature/package info is available.","Catch the RuntimeException in the service boundary and return a proper billing error response code instead of crashing."],"exampleFix":"// before\nval skuDetails = billing.getSkuDetails(api, pkg, type, extras)\n// after\nif (context.packageManager.getLaunchIntentForPackage(pkg) == null) {\n    return BillingError.UNKNOWN_ERROR // fail fast before remote call\n}\nval skuDetails = billing.getSkuDetails(api, pkg, type, extras)","handlingStrategy":"validation","validationCode":"try {\n    context.packageManager.getPackageInfo(callerPkg, 0)\n} catch (e: PackageManager.NameNotFoundException) {\n    return BillingError.UNKNOWN_ERROR // caller package resolvable before IAP call\n}","typeGuard":"fun Context.canResolvePackage(pkg: String): Boolean =\n    runCatching { packageManager.getPackageInfo(pkg, 0) }.isSuccess","tryCatchPattern":"try {\n    billing.consumePurchase(...)\n} catch (e: RuntimeException) {\n    if (e.message?.contains(\"client information\") == true) reportBadCallerPackage()\n    else throw e\n}","preventionTips":["Pass the correct, installed caller package name in billing extras","Declare package-visibility queries for Android 11+","Reinstall caller apps whose signatures are unavailable","Return a billing response code instead of crashing the service"],"tags":["android","package-manager","in-app-billing","microg"],"backgroundTag":"resource-not-found","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}