microg/GmsCore · error · AssetPackException
APP_UNAVAILABLE
APP_UNAVAILABLE
Error message
e.message
What it means
getAppVersionCode wraps PackageManager.NameNotFoundException into AssetPackException(APP_UNAVAILABLE, e.message). The message surfaced ('e.message') is the underlying NameNotFoundException text, typically the package name that could not be resolved. It means the queried package is not installed on the device.
Solutions
- Verify the package name spelling and that the app is installed before querying its version code
- Catch AssetPackException with APP_UNAVAILABLE and prompt install via Play
- Re-check installation state at the moment of the call (handle races)
- For asset packs, ensure the base app is installed and Play Core is current
Example fix
// before
val versionCode = getAppVersionCode(context, packageName)!!
// after
try {
val versionCode = getAppVersionCode(context, packageName)
} catch (e: AssetPackException) {
if (e.errorCode == AssetPackErrorCode.APP_UNAVAILABLE) {
// trigger install / show unavailable state
}
} Defensive patterns
Strategy: try-catch
Validate before calling
fun isPackageInstalled(pm: PackageManager, name: String) =
try { pm.getPackageInfo(name, 0); true } catch (e: PackageManager.NameNotFoundException) { false } Try / catch
try {
val code = getAppVersionCode(context, packageName)
} catch (e: AssetPackException) {
if (e.errorCode == AssetPackErrorCode.APP_UNAVAILABLE) {
// route user to Play Store install
}
} Prevention
- Check installation state before reading package metadata
- Validate package name spelling/constant
- Handle uninstall races by re-checking before dependent operations
When it happens
Trigger: Calling getAppVersionCode for a packageName that has no PackageInfo — i.e., getPackageInfo throws PackageManager.NameNotFoundException.
Common situations: Play Asset Pack requested for an app that is not installed; typo in package name; instant/asset module delivered before the base app installs; uninstall between check and query.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- IntegrityErrorCode.NONCE_TOO_LONG
- IntegrityErrorCode.NONCE_TOO_SHORT
- Missing package name
- A path must start with a single / .
- Access denied, missing google package permission for
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/0b86bd89db4feb21.
Report an issue: GitHub.
Appendix: source
Thrown at vending-app/src/main/kotlin/com/google/android/finsky/extensions.kt:52
import org.microg.vending.billing.GServices
import org.microg.vending.billing.core.GooglePlayApi
import org.microg.vending.billing.core.HttpClient
import java.io.File
import java.util.Collections
const val KEY_MODULE_NAME = "module_name"
const val TAG_REQUEST = "asset_module"
private const val ASSET_MODULE_DELIVERY_URL = "https://play-fe.googleapis.com/fdfe/assetModuleDelivery"
private const val TAG = "AssetModuleRequest"
fun getAppVersionCode(context: Context, packageName: String): Long? {
return try {
PackageInfoCompat.getLongVersionCode(context.packageManager.getPackageInfo(packageName, 0))
} catch (e: PackageManager.NameNotFoundException) {
throw AssetPackException(AssetPackErrorCode.APP_UNAVAILABLE, e.message)
}
}
fun <T> Bundle?.get(key: BundleKeys.RootKey<T>): T? = if (this == null) null else BundleKeys.get(this, key)
fun <T> Bundle?.get(key: BundleKeys.RootKey<T>, def: T): T = if (this == null) def else BundleKeys.get(this, key, def)
fun <T> Bundle.put(key: BundleKeys.RootKey<T>, v: T) = BundleKeys.put(this, key, v)
fun <T> Bundle.put(key: BundleKeys.PackKey<T>, packName: String, v: T) = BundleKeys.put(this, key, packName, v)
fun <T> Bundle.put(key: BundleKeys.SliceKey<T>, packName: String, sliceId: String, v: T) = BundleKeys.put(this, key, packName, sliceId, v)
fun <T> bundleOf(pair: Pair<BundleKeys.RootKey<T>, T>): Bundle = Bundle().apply { put(pair.first, pair.second) }
operator fun Bundle.plus(other: Bundle): Bundle = Bundle(this).apply { putAll(other) }
operator fun <T> Bundle.plus(pair: Pair<BundleKeys.RootKey<T>, T>): Bundle = this + bundleOf(pair)
val Context.assetPacksDir: File
get() = File(filesDir, "assetpacks")
fun Context.getSessionDir(sessionId: Int) =
File(assetPacksDir, sessionId.toString())
fun Context.getModuleDir(sessionId: Int, moduleName: String): File =
File(getSessionDir(sessionId), moduleName)View on GitHub (pinned to 157c9d86ac)