{"record":{"id":"807ab8644344b171","repo":"microg/GmsCore","slug":"nothing-cached-cachekey","errorCode":null,"errorMessage":"Nothing cached: $cacheKey","messagePattern":"Nothing cached: \\$cacheKey","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt","lineNumber":149,"sourceCode":"            buyFlowCacheEntry.lastAcquireResult = coreResult\n            if (coreResult.acquireParsedResult.action?.droidGuardMap?.isNotEmpty() == true) {\n                DroidGuardClient.getResults(context, \"phonesky_acquire_flow\", coreResult.acquireParsedResult.action.droidGuardMap).addOnCompleteListener { task ->\n                    buyFlowCacheEntry.droidGuardResult = task.result\n                }\n            }\n            coreResult.acquireParsedResult.purchaseItems.forEach {\n                PurchaseManager.addPurchase(buyFlowCacheEntry.account, buyFlowCacheEntry.packageName, it)\n            }\n            return BuyFlowResult(\n                coreResult.acquireParsedResult,\n                buyFlowCacheEntry.account,\n                coreResult.acquireParsedResult.result.toBundle()\n            )\n        }\n\n        fun requestAuthProofToken(context: Context, cacheKey: String, password: String): String {\n            val buyFlowCacheEntry = buyFlowCacheMap[cacheKey]\n                ?: throw IllegalStateException(\"Nothing cached: $cacheKey\")\n            val deferred = CoroutineScope(Dispatchers.IO).async {\n                createIAPCore(\n                    context,\n                    buyFlowCacheEntry.account,\n                    buyFlowCacheEntry.packageName\n                ).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            }","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt#L131-L167","documentation":"InAppBillingServiceImpl.requestAuthProofToken looks up a previously cached buy-flow entry from buyFlowCacheMap using the caller-supplied cacheKey and throws this IllegalStateException when the key is absent. It means the auth-proof-token request was made without the buy flow first having stored its state under that key.","triggerScenarios":"Calling requestAuthProofToken(context, cacheKey, password) with a key never populated by a prior acquire/buy-flow step, or after the cache entry was cleared/evicted, or from a different service instance than the one that populated the map.","commonSituations":"Client passes a stale cacheKey from an earlier session; buy-flow creation failed earlier but the client proceeded; service process was killed, losing the in-memory cache; key typo/protocol mismatch between caller and service.","solutions":["Perform the initial buy-intent/acquire flow that populates buyFlowCacheMap before requesting an auth proof token, and reuse the exact key it returned.","Persist or re-acquire the cache entry if the service process may have restarted (in-memory map is volatile).","Validate the cacheKey on the client side before binding the call.","Handle IllegalStateException in the client and restart the buy flow from the beginning."],"exampleFix":"// before\nval token = billing.requestAuthProofToken(context, staleKey, password)\n// after\nval token = if (hasBuyFlowCache(staleKey)) billing.requestAuthProofToken(context, staleKey, password)\n            else runCatching { startBuyFlow(); requestAuthProofToken(context, newKey, password) }\n                .getOrThrow()","handlingStrategy":"validation","validationCode":"if (!hasBuyFlowCacheEntry(cacheKey)) {\n    throw IllegalStateException(\"Start buy flow first\")\n}\nval token = requestAuthProofToken(context, cacheKey, password)","typeGuard":null,"tryCatchPattern":"try {\n    val token = requestAuthProofToken(context, cacheKey, password)\n} catch (e: IllegalStateException) {\n    restartBuyFlow() // cache lost or stale\n}","preventionTips":["Always run the buy-intent flow before requesting auth proof tokens","Reuse the exact cacheKey returned by the earlier step","Remember the cache is in-memory: re-acquire after process death","Never persist cacheKeys across sessions"],"tags":["android","in-app-billing","cache","state"],"backgroundTag":"record-not-found","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}