microg/GmsCore · error · NullPointerException

AcknowledgePurchaseResponse PurchaseItem is null

Error message

AcknowledgePurchaseResponse PurchaseItem is null

What it means

AcknowledgePurchaseResult.parseFrom throws this NullPointerException when the AcknowledgePurchaseResponse is non-null but its purchaseItem field is null. A well-formed acknowledge/purchase response must carry exactly one purchase item; without it the library cannot build a result, so it fails fast with a descriptive message.

Source

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

) : 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. Verify the purchase token passed to acknowledgePurchase is valid and belongs to the current user
  2. Log the raw response bytes and decode to confirm purchaseItem is genuinely absent
  3. Update microG/Play Services so the billing backend returns complete responses
  4. Catch NullPointerException from parseFrom and treat it as a failed acknowledge (RESPONSE_CODE != 0)

Example fix

// before
val result = iapCore.acknowledgePurchase(params)
// after
val result = try {
    iapCore.acknowledgePurchase(params)
} catch (e: NullPointerException) {
    AcknowledgePurchaseResult(null, mapOf("RESPONSE_CODE" to -1, "DEBUG_MESSAGE" to e.message ?: ""))
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (ack.purchaseItem == null) {
    // handle missing purchase item before parsing
}

Type guard

fun AcknowledgePurchaseResponse.hasPurchaseItem(): Boolean = this.purchaseItem != null

Try / catch

try {
    AcknowledgePurchaseResult.parseFrom(ack)
} catch (e: NullPointerException) {
    // map to RESPONSE_CODE failure
}

Prevention

When it happens

Trigger: Server returns an AcknowledgePurchaseResponse with failedResponse == null but purchaseItem == null — i.e. an otherwise successful-looking response body that contains no purchase item data.

Common situations: Partial or truncated protobuf responses from Google Play/Vending; servers replying OK to an acknowledge for a purchase token that does not exist; outdated microG/vendor implementations returning incomplete payloads.

Related errors


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