microg/GmsCore · error · RuntimeException

oauthToken is null

Error message

oauthToken is null

What it means

The same requestGellerOauthToken function throws RuntimeException("oauthToken is null") when AccountManager.blockingGetAuthToken returns null for a valid account — the account exists but no auth token could be issued for the webhistory scope.

Source

Thrown at play-services-core/src/main/kotlin/com/google/android/gms/semanticlocationhistory/extensions.kt:50

const val E2EE_TYPE_URL = "type.googleapis.com/geller.oneplatform.GellerE2eeElement"
const val AES_GCM_IV_SIZE = 12
const val AES_GCM_TAG_BITS = 128
const val AES_KEY_SIZE = 32

const val SEMANTIC_TYPE_HOME = 1
const val SEMANTIC_TYPE_WORK = 2
const val SEARCH_WINDOW_DAYS = 30L
const val SECONDS_PER_DAY = 86400L

suspend fun Context.requestGellerOauthToken(accountName: String, scope: String = "oauth2:https://www.googleapis.com/auth/webhistory"): String {
    val accountManager = AccountManager.get(this)
    val account = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).find {
        it.name == accountName
    }
    if (account == null) throw RuntimeException("account is null")
    return withContext(Dispatchers.IO) {
        accountManager.blockingGetAuthToken(account, scope, true)
    } ?: throw RuntimeException("oauthToken is null")
}

suspend fun Context.getObfuscatedGaiaId(accountName: String) = requestGellerOauthToken(accountName, AuthConstants.SCOPE_GET_ACCOUNT_ID)

private val weakCachedKeyMap = WeakHashMap<String, List<Pair<ByteArray, Int>>>()

fun loadKeyMaterials(context: Context, accountName: String): List<Pair<ByteArray, Int>> {
    val result = weakCachedKeyMap.get(accountName)
    if (!result.isNullOrEmpty()) {
        return result
    }
    val keyManager = LocalKeyManager.getInstance(context)
    val keys = keyManager.getKeysForDomain(accountName, ODLH_SECURITY_DOMAIN)
        .ifEmpty { keyManager.getKeysForDomain(accountName, ODLH_SECURITY_DOMAIN_SHORT) }
    val materials = keys.mapNotNull { key ->
        val material = key.keyMaterial?.toByteArray() ?: return@mapNotNull null
        if (material.size != AES_KEY_SIZE) return@mapNotNull null
        material to (key.keyVersion ?: 0)

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Invalidate the stale token (accountManager.invalidateAuthToken) and retry the request
  2. Check the account's auth state and prompt the user to sign in again
  3. Ensure microG's auth backend can reach Google servers (network/proxy checks)
  4. Catch RuntimeException and fall back to an unauthenticated / degraded feature path

Example fix

// before
val token = context.requestGellerOauthToken(accountName)
// after
val token = try {
    context.requestGellerOauthToken(accountName)
} catch (e: RuntimeException) {
    Log.w(TAG, "geller oauth token unavailable", e); null
}
Defensive patterns

Strategy: retry

Validate before calling

val account = AccountManager.get(context).findAccount(accountName) ?: return null
val hasAuth = true // ensure account is not flagged for re-auth in account settings

Type guard

suspend fun Context.safeGellerToken(accountName: String): String? =
    try { requestGellerOauthToken(accountName) } catch (e: RuntimeException) { null }

Try / catch

try {
    val token = context.requestGellerOauthToken(accountName)
} catch (e: RuntimeException) {
    accountManager.invalidateAuthToken(account.type, null)
    retryWithReauth()
}

Prevention

When it happens

Trigger: blockingGetAuthToken returns null: the account's auth session is expired, the user has not granted the auth scope, the account needs re-authentication (e.g. after password change), or AccountManager could not contact the auth backend (network/timeout is usually surfaced differently, but null can occur).

Common situations: Devices with stale Google credentials, accounts flagged for re-authentication, or the geller/webhistory scope being denied for the account on microG.

Related errors


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