microg/GmsCore · critical · RuntimeException

Failed to obtain login token.

Error message

Failed to obtain login token.

What it means

createIAPCore builds an IAPCore using auth data from AuthManager.getAuthData; when it returns null (no login token for the account) this RuntimeException is thrown. It means the device has no usable Google auth token for the given account, so IAP API calls cannot be authenticated.

Source

Thrown at vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt:169

                createIAPCore(
                    context,
                    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. Ensure the device has a signed-in Google account and the app targets the correct account name.
  2. Trigger account re-authentication (re-add account or refresh credentials) so AuthManager can obtain a token.
  3. Check network connectivity and microG auth component health; retry after token refresh succeeds.
  4. Catch this RuntimeException in the billing path and surface a 'sign-in required' state to the user.

Example fix

// before
val history = billing.getPurchaseHistory(api, pkg, type, extras)
// after
try {
    val history = billing.getPurchaseHistory(api, pkg, type, extras)
} catch (e: RuntimeException) {
    if (e.message == "Failed to obtain login token.") promptSignIn()
    else throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

val accounts = AccountManager.get(context).getAccountsByType("com.google")
if (accounts.isEmpty()) promptSignIn() else proceedBilling()

Type guard

fun hasGoogleAuth(account: Account?, context: Context): Boolean =
    account != null && AuthManager.getAuthData(context, account) != null

Try / catch

try {
    billing.getPurchaseHistory(...)
} catch (e: RuntimeException) {
    if (e.message?.contains("login token") == true) promptReAuth()
    else throw e
}

Prevention

When it happens

Trigger: Any billing call (acquireRequest, getPurchaseHistory, consumePurchaseExtraParams, getSkuDetailsExtraParams, acknowledgePurchase, requestAuthProofToken) that goes through createIAPCore while AuthManager.getAuthData(context, account) returns null — no cached/refreshable auth token.

Common situations: Device not signed in or account removed; auth token refresh failing due to network/auth server issues; microG not permitted to fetch auth tokens; account credentials invalidated (password change, security events).

Related errors


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