{"record":{"id":"dc80de916ca64c81","repo":"microg/GmsCore","slug":"network-request-failed-message-e-message","errorCode":null,"errorMessage":"Network request failed. message=${e.message}","messagePattern":"Network request failed\\. message=(.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"vending-app/src/main/java/org/microg/vending/billing/core/IAPCore.kt","lineNumber":140,"sourceCode":"            val cacheEntry = skuDetailsCache.get(requestBody)\n            if (cacheEntry != null) {\n                val getSkuDetailsResult = GetSkuDetailsResult.parseFrom(GoogleApiResponse.ADAPTER.decode(cacheEntry).payload?.skuDetailsResponse)\n                if (getSkuDetailsResult.skuDetailsList != null && getSkuDetailsResult.skuDetailsList.isNotEmpty()) {\n                    Log.d(\"IAPCore\", \"getSkuDetails from cache \")\n                    return getSkuDetailsResult\n                }\n            }\n            Log.d(\"IAPCore\", \"getSkuDetails: \")\n            val response = HttpClient().post(\n                GooglePlayApi.URL_SKU_DETAILS,\n                headers = HeaderProvider.getDefaultHeaders(authData, deviceInfo),\n                payload = skuDetailsRequest,\n                adapter = GoogleApiResponse.ADAPTER\n            )\n            skuDetailsCache.put(requestBody, response.encode())\n            GetSkuDetailsResult.parseFrom(response.payload?.skuDetailsResponse)\n        } catch (e: Exception) {\n            throw RuntimeException(\"Network request failed. message=${e.message}\")\n        }\n    }\n\n    private fun createAcquireRequest(params: AcquireParams): AcquireRequest {\n        val theme = 2\n\n        val skuPackageName = params.buyFlowParams.skuParams[\"skuPackageName\"] ?: clientInfo.pkgName\n        val extendedPackageInfo = ExtendedPackageInfo(context, skuPackageName as String)\n        val docId = if (params.buyFlowParams.skuSerializedDockIdList?.isNotEmpty() == true) {\n            val sDocIdBytes = Base64.decode(params.buyFlowParams.skuSerializedDockIdList[0], Base64.URL_SAFE + Base64.NO_WRAP)\n            DocId.ADAPTER.decode(sDocIdBytes)\n        } else {\n            val docIdBuilder = DocId.Builder()\n            docIdBuilder.apply {\n                backendDocId =\n                    \"${params.buyFlowParams.skuType}:$skuPackageName:${params.buyFlowParams.sku}\"\n                type = getSkuType(params.buyFlowParams.skuType)\n                backend = 3","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/vending-app/src/main/java/org/microg/vending/billing/core/IAPCore.kt#L122-L158","documentation":"IAPCore.getSkuDetails wraps every exception from the SKU-details network round trip (HTTP call, response decode, result parsing) in a RuntimeException with the message 'Network request failed. message=...'. The original exception type is lost; only its message is preserved.","triggerScenarios":"Calling getSkuDetails when the HTTP request throws (no network, timeout, non-200 status from HttpClient.get), the protobuf decode fails, or GetSkuDetailsResult.parseFrom throws (null/invalid payload).","commonSituations":"Device offline or Play Services unreachable; microG not signed in to a Google account; server returning unexpected payload causing parseFrom to throw; HTTP 4xx/5xx from the billing endpoint.","solutions":["Check device connectivity and that Google Play/microG account is signed in before calling","Read e.message to identify the underlying cause (status code, null payload, etc.) since the original exception is wrapped","Catch RuntimeException around getSkuDetails and surface a retryable billing error","Retry with exponential backoff for transient network failures"],"exampleFix":"// before\nval details = iapCore.getSkuDetails(params)\n// after\nval details = try {\n    iapCore.getSkuDetails(params)\n} catch (e: RuntimeException) {\n    Log.w(\"Billing\", \"getSkuDetails failed: ${e.message}\")\n    null\n}","handlingStrategy":"try-catch","validationCode":"if (!isOnline(context)) return\nrequire(accountSignedIn) { \"Google account required for getSkuDetails\" }","typeGuard":null,"tryCatchPattern":"try {\n    iapCore.getSkuDetails(params)\n} catch (e: RuntimeException) {\n    Log.w(\"Billing\", \"getSkuDetails failed: ${e.message}\")\n    retryWithBackoff()\n}","preventionTips":["Check connectivity before billing calls","Ensure the user has a Google account configured in Play/microG","Remember e.message is the only diagnostic — enable HTTP logging for more detail","Use exponential backoff retries for transient failures"],"tags":["network","runtimeexception","billing","wrapper"],"backgroundTag":"network-request-failed","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"}