microg/GmsCore · error · NullPointerException

response is null

Error message

response is null

What it means

AcknowledgePurchaseResult.parseFrom throws this NullPointerException when the raw AcknowledgePurchaseResponse passed to it is null. The library treats a missing protobuf response as a programming/transport invariant violation rather than a normal IAP failure, so it fails fast instead of building a result object from nothing.

Source

Thrown at vending-app/src/main/java/org/microg/vending/billing/core/AcknowledgePurchaseResult.kt:17

package org.microg.vending.billing.core

import org.microg.vending.billing.proto.AcknowledgePurchaseResponse

class AcknowledgePurchaseResult(
    val purchaseItem: PurchaseItem? = null,
    resultMap: Map<String, Any> = mapOf(
        "RESPONSE_CODE" to 0,
        "DEBUG_MESSAGE" to ""
    )
) : IAPResult(resultMap) {
    companion object {
        fun parseFrom(
            response: AcknowledgePurchaseResponse?
        ): AcknowledgePurchaseResult {
            if (response == null) {
                throw NullPointerException("response is null")
            }
            if (response.failedResponse != null) {
                return AcknowledgePurchaseResult(
                    null,
                    mapOf(
                        "RESPONSE_CODE" to (response.failedResponse?.statusCode ?: 0),
                        "DEBUG_MESSAGE" to (response.failedResponse?.msg ?: "")
                    )
                )
            }
            if (response.purchaseItem == null) {
                throw NullPointerException("AcknowledgePurchaseResponse PurchaseItem is null")
            }
            if (response.purchaseItem?.purchaseItemData?.size != 1)
                throw IllegalStateException("AcknowledgePurchaseResult purchase item count != 1")
            return AcknowledgePurchaseResult(parsePurchaseItem(response.purchaseItem!!).getOrNull(0))
        }
    }

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Check the enclosing response payload before calling parseFrom: only call it when response.payload?.acknowledgePurchaseResponse != null
  2. Inspect the raw network response (enable logging in HttpClient) to see why the server omitted acknowledgePurchaseResponse
  3. Ensure Google Play / microG services are up to date so the server returns a well-formed response
  4. Wrap the call in try-catch for NullPointerException and surface a friendly billing-unavailable error

Example fix

// before
val result = AcknowledgePurchaseResult.parseFrom(response.payload?.acknowledgePurchaseResponse)
// after
val ack = response.payload?.acknowledgePurchaseResponse
val result = if (ack != null) AcknowledgePurchaseResult.parseFrom(ack) else AcknowledgePurchaseResult(null, mapOf("RESPONSE_CODE" to -1, "DEBUG_MESSAGE" to "empty acknowledge response"))
Defensive patterns

Strategy: type-guard

Validate before calling

val ack = response.payload?.acknowledgePurchaseResponse
requireNotNull(ack) { "acknowledgePurchaseResponse missing from payload" }

Type guard

fun AcknowledgePurchaseResponse?.isValid(): Boolean = this != null

Try / catch

try {
    AcknowledgePurchaseResult.parseFrom(response.payload?.acknowledgePurchaseResponse)
} catch (e: NullPointerException) {
    // treat as failed acknowledge
}

Prevention

When it happens

Trigger: Calling AcknowledgePurchaseResult.parseFrom(null), typically when the enclosing GoogleApiResponse has payload == null or payload.acknowledgePurchaseResponse == null (e.g. the Play Billing/Vending server returned an empty or malformed response body that decoded to no acknowledgePurchaseResponse).

Common situations: Users on broken/modified microG or Play Services setups where the Google Play billing endpoint returns an empty payload; apps calling acknowledgePurchase() against a corrupted protobuf response; unit tests passing null directly.

Related errors


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