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
- Verify the purchase token passed to acknowledgePurchase is valid and belongs to the current user
- Log the raw response bytes and decode to confirm purchaseItem is genuinely absent
- Update microG/Play Services so the billing backend returns complete responses
- 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
- Validate the purchase token exists before acknowledging
- Decode and inspect the raw protobuf when purchaseItem is unexpectedly absent
- Treat a null purchaseItem as a failed response, not a crash
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
- response is null
- AcknowledgePurchaseResult purchase item count != 1
- key data missing
- rolling start interval number missing
- rolling period missing
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/4cbb8c10b26faa3f.
Report an issue: GitHub.