microg/GmsCore · error · RuntimeException
account is null
Error message
account is null
What it means
requestGellerOauthToken looks up an AccountManager account of the default type matching the given accountName and throws RuntimeException("account is null") if no such account exists on the device. The caller (e.g. getObfuscatedGaiaId) therefore requires a signed-in matching Google account.
Source
Thrown at play-services-core/src/main/kotlin/com/google/android/gms/semanticlocationhistory/extensions.kt:47
const val ODLH_SECURITY_DOMAIN = "users/me/securitydomains/on_device_location_history"
const val ODLH_SECURITY_DOMAIN_SHORT = "on_device_location_history"
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 ->View on GitHub (pinned to 157c9d86ac)
Solutions
- Verify the account exists before calling: AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).any { it.name == accountName }
- Re-query the account list instead of caching the account name across sign-out events
- Trigger the account add/sign-in flow if the account is missing
- Catch RuntimeException in the caller and prompt for re-authentication
Example fix
// before
val gaiaId = context.getObfuscatedGaiaId(accountName)
// after
val account = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).find { it.name == accountName }
val gaiaId = if (account != null) context.getObfuscatedGaiaId(accountName) else null Defensive patterns
Strategy: type-guard
Validate before calling
val exists = AccountManager.get(context)
.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)
.any { it.name == accountName }
if (!exists) promptSignIn() else context.getObfuscatedGaiaId(accountName) Type guard
fun Context.findAccount(accountName: String): Account? =
AccountManager.get(this).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)
.firstOrNull { it.name == accountName } Try / catch
try {
val gaiaId = context.getObfuscatedGaiaId(accountName)
} catch (e: RuntimeException) {
handleMissingAccount(accountName)
} Prevention
- Re-resolve accounts instead of caching account names across sessions
- Listen for LOGIN_ACCOUNTS_CHANGED_ACTION to refresh cached account names
- Compare account names case-sensitively as AccountManager does
When it happens
Trigger: Calling getObfuscatedGaiaId / requestGellerOauthToken with an accountName string that does not exactly match any registered account of AuthConstants.DEFAULT_ACCOUNT_TYPE — account not signed in, typo, different casing, or account removed since it was cached.
Common situations: Semantic location history features running for an account that was signed out or removed from the device, or a stale account name persisted in app settings.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
- Required caller information missing
- oauthToken is null
- oauthToken is null
- Failed to obtain login token.
- No Google account found.
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/17a9d56471c5b958.
Report an issue: GitHub.