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

  1. Verify microG's device-spoof/profile configuration is complete and valid.
  2. Run on a device/ROM exposing the standard Android build properties createDeviceEnvInfo reads.
  3. Update microG to a version handling your environment's property set.
  4. 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

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


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/9702081c0db29686. Report an issue: GitHub.