microg/GmsCore · critical · RuntimeException
Failed to retrieve device information.
Error message
Failed to retrieve device information.
What it means
createIAPCore calls createDeviceEnvInfo(context) to assemble device environment information required by the IAP backend; a null result triggers this RuntimeException. It means required device metadata (build/environment info) could not be produced, so the IAPCore cannot be constructed.
Source
Thrown at vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt:171
buyFlowCacheEntry.account,
buyFlowCacheEntry.packageName
).requestAuthProofToken(password)
}
return runBlocking { deferred.await() }
}
private fun createIAPCore(context: Context, account: Account, pkgName: String): IAPCore {
val key = "$pkgName:${account.name}"
val cacheEntry = iapCoreCacheMap[key]
if (cacheEntry != null) {
if (cacheEntry.expiredAt > System.currentTimeMillis())
return cacheEntry.iapCore
iapCoreCacheMap.remove(key)
}
val authData = AuthManager.getAuthData(context, account)
?: throw RuntimeException("Failed to obtain login token.")
val deviceEnvInfo = createDeviceEnvInfo(context)
?: throw RuntimeException("Failed to retrieve device information.")
val clientInfo = createClient(context, pkgName)
?: throw RuntimeException("Failed to retrieve client information.")
val iapCore = IAPCore(context.applicationContext, deviceEnvInfo, clientInfo, authData)
iapCoreCacheMap[key] =
IAPCoreCacheEntry(iapCore, System.currentTimeMillis() + EXPIRE_MS)
return iapCore
}
}
private fun getPreferredAccount(extraParams: Bundle?): Account {
val name = extraParams?.getString("accountName")
name?.let {
extraParams.remove("accountName")
}
return getGoogleAccount(context, name)
?: throw RuntimeException("No Google account found.")
}
View on GitHub (pinned to 157c9d86ac)
Solutions
- Verify microG's device-spoof/profile configuration is complete and valid.
- Run on a device/ROM exposing the standard Android build properties createDeviceEnvInfo reads.
- Update microG to a version handling your environment's property set.
- Catch the RuntimeException and degrade gracefully (disable billing features) instead of crashing.
Example fix
// before
val result = billing.getSkuDetails(api, pkg, type, extras)
// after
val result = try {
billing.getSkuDetails(api, pkg, type, extras)
} catch (e: RuntimeException) {
Log.e(TAG, "IAP unavailable: ${e.message}"); null
} Defensive patterns
Strategy: try-catch
Validate before calling
val props = setOf("ro.build.fingerprint", "ro.product.model")
if (props.any { System.getProperty(it).isNullOrBlank() }) failFast("Device info incomplete") Try / catch
try {
billing.getSkuDetails(...)
} catch (e: RuntimeException) {
if (e.message?.contains("device information") == true) degradeGracefully()
else throw e
} Prevention
- Ensure microG device spoof/profile settings are complete
- Test on standard ROMs/emulators with typical build properties
- Keep microG updated for broader device-info coverage
- Gate billing features behind a startup capability check
When it happens
Trigger: Any billing API routed through createIAPCore when createDeviceEnvInfo returns null — typically missing system properties/package context needed to build the device environment blob.
Common situations: Running in an environment with unusual/missing build fingerprint properties (emulator, custom ROM); microG build mismatch; context lacking expected package info; spoofed-device configuration incomplete.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Failed to obtain login token.
- Failed to retrieve client information.
- Access denied, missing google package permission for
- Required caller information missing
- ERROR_MISSING_INSTANCEID_SERVICE
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/9702081c0db29686.
Report an issue: GitHub.