---
title: "What does Play Billing ITEM_NOT_OWNED (8) mean?"
description: "ITEM_NOT_OWNED (8) means the user does not own the product you tried to replace, acknowledge or consume. Query purchases first and reconcile."
url: https://revenuedot.app/docs/errors/play-billing-item-not-owned
---

# What does Play Billing ITEM_NOT_OWNED (8) mean?

Play Billing ITEM_NOT_OWNED (8) means the action failed because the user does not own the item it targeted.

## Quick facts

| | |
|---|---|
| Error | `BillingClient.BillingResponseCode.ITEM_NOT_OWNED` (8) |
| Where | Google Play Billing Library (`BillingResult.responseCode`) |
| What the vendor says | The requested action on the item failed because the user does not own it. |

## Cause

- Google says the user does not own the subscription or one-time product they tried to replace, acknowledge or consume. It is not transient in most cases, except when Google Play's cache is stale.
- A stale cache is refreshed when the error is received, so the data is correct on the next call.
- Google's own example: you try to consume an item and the updated purchase data says it is already consumed, so the error can be ignored.

## Fix

1. Call `queryPurchasesAsync()` after the error to get the current purchases.
2. If the updated purchase list shows the item is already consumed, ignore the error. If the user owns it, redo the action.
3. If the user does not own it at all, stop the action; do not grant access.
4. Make acknowledge and consume calls idempotent, keyed by the purchase token.

## Example

```kotlin
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.QueryPurchasesParams

// After ITEM_NOT_OWNED, trust the fresh purchase list, not the purchase you held: it may already be consumed.
fun onAcknowledgeResult(client: BillingClient, result: BillingResult) {
    if (result.responseCode == BillingClient.BillingResponseCode.ITEM_NOT_OWNED) {
        val params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build()
        client.queryPurchasesAsync(params) { _, purchases ->
            println("The user currently owns ${purchases.size} one-time products")
        }
    }
}
```

*Not compiled: this Kotlin snippet was not built here because the docs repo has no Kotlin or Android toolchain. Check it against your Play Billing Library or SDK version before you ship it.*

## How the RevenueDot SDK reports it

The RevenueDot `purchases-android` fork maps `ITEM_NOT_OWNED` to `PurchasesErrorCode.PurchaseNotAllowedError` (code 3). See [what purchaseNotAllowedError means](https://revenuedot.app/docs/errors/sdk-purchase-not-allowed-error.md).

## Related

- [What does Play Billing ITEM_ALREADY_OWNED (7) mean?](https://revenuedot.app/docs/errors/play-billing-item-already-owned.md)
- [What does purchaseNotAllowedError (code 3) mean in the purchases SDK?](https://revenuedot.app/docs/errors/sdk-purchase-not-allowed-error.md)
- [What does Play Billing DEVELOPER_ERROR (5) mean?](https://revenuedot.app/docs/errors/play-billing-developer-error.md)

## Source

- [Google: BillingResponseCode.ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode)
- [Google: Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors)
- [RevenueDot purchases-android: google/errors.kt (how the SDK maps response codes)](https://github.com/revenuedot/purchases-android/blob/revenuedot/main-patches/purchases/src/main/kotlin/com/revenuecat/purchases/google/errors.kt)

Checked: 2026-10-03
