К основному содержанию
скилл CX Codex

rc-error-handling — скилл для Claude Code: ошибки RevenueCat Android

Разбирает ошибки RevenueCat Android SDK: какой код что значит и что показать пользователю. Пригодится, когда платёжный флоу ломается на проде.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add RevenueCat/ai-toolkit --skill rc-error-handling -a claude-code
Открыть на GitHub

Что делает rc-error-handling

Скилл описывает работу с PurchasesError вместо ручного перебора BillingResponseCode из Google Play Billing. Внутри — разбор PurchasesErrorCode, таблица кодов с рекомендованной реакцией интерфейса и готовые шаблоны catch-блоков на Kotlin.

Главное правило: awaitPurchase() бросает PurchasesTransactionException с флагом userCancelled, а остальные вызовы (awaitOfferings, awaitGetProducts, awaitCustomerInfo, awaitRestore) — PurchasesException. Отмену пользователем проверяют первой и молча выходят, дальше ветвление по error.code. Строку error.message отправляют в логи, а не в UI: для интерфейса держат одну функцию-маппер.

SDK сам повторяет временные сбои биллинга и сети, поэтому до вас доходят только ошибки с исчерпанным бюджетом ретраев. Свой backoff-цикл вокруг вызовов добавлять не нужно — это сломает задуманное поведение. Единственный ретрай, который имеет смысл, — кнопка «Try Again» по нажатию пользователя.

Какие задачи решает

  • различить отмену покупки пользователем и настоящую ошибку
  • показать понятный текст вместо технической строки из SDK
  • обработать зависшую покупку в статусе pending
  • подтянуть актуальные entitlements, если товар уже куплен
  • пережить потерю сети при загрузке офферов

Примеры запросов агенту

  • Разбери обработку ошибок в этом вызове awaitPurchase по скиллу rc-error-handling
  • Проверь, что я сначала смотрю userCancelled, а потом error.code
  • Напиши userFacingMessage для PurchasesErrorCode по таблице из скилла

Как установить rc-error-handling

1Через Skills CLI (Vercel)

npx skills add RevenueCat/ai-toolkit --skill rc-error-handling -a claude-code

2Вручную: положить файлы

~/.claude/skills/rc-error-handling/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/rc-error-handling/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о rc-error-handling

Как установить rc-error-handling в Claude?

Выполните npx skills add RevenueCat/ai-toolkit --skill rc-error-handling -a claude-code. После этого скилл окажется в ~/.claude/skills/rc-error-handling/SKILL.md.

Что делает rc-error-handling?

Подсказывает агенту, как обрабатывать ошибки RevenueCat Android SDK: какой тип исключения ловить, как ветвить по PurchasesErrorCode и какой текст показать пользователю.

Нужно ли писать свой retry-цикл вокруг вызовов SDK?

Нет. SDK уже повторяет временные сбои биллинга и сети, и любая дошедшая до вас ошибка означает, что бюджет ретраев исчерпан. Оставьте только повтор по кнопке от пользователя.

Исходный текст

SKILL.md · MIT
---
name: rc-error-handling
description: Use this skill when handling errors from the RevenueCat Android SDK. Covers PurchasesError, the PurchasesErrorCode enum, the userCancelled flag on PurchasesTransactionException, and the recommended UI response per code.
license: Apache-2.0; see LICENSE
metadata:
  author: RevenueCat
  source: revenuecat-handbook chapter 8
  keywords:
  - android
  - revenuecat
  - error-handling
  - purchases-error
  - purchases-error-code
  - purchases-transaction-exception
---

# Error Handling

## Phase 1: Understand

With raw Google Play Billing you enumerate every `BillingResponseCode`, split them into retriable and non retriable groups, and build backoff retry logic. RevenueCat collapses this into a single type you deal with: `PurchasesError`.

```kotlin
public class PurchasesError(
    val code: PurchasesErrorCode,
    val underlyingErrorMessage: String? = null,
) {
    val message: String // technical description, for logs
}
```

Key facts you rely on:

- `PurchasesErrorCode` is a cross platform enum with stable, readable codes.
- `error.message` is a technical string. It belongs in logs, not in the UI.
- `awaitPurchase()` throws `PurchasesTransactionException`, which adds a `userCancelled: Boolean` flag.
- Every other `await*` call (`awaitOfferings`, `awaitGetProducts`, `awaitCustomerInfo`, `awaitRestore`) throws `PurchasesException`.
- The SDK already retries transient billing and network failures internally. Any error that reaches you has exhausted the SDK retry budget. You do not add your own backoff loop. The only retry you implement is a user triggered "Try Again" button.

## Phase 2: Plan

Before writing a `catch` block, decide three things:

1. Which `await*` call are you wrapping? That picks the exception type.
2. Which codes have specific handling? Everything else falls into a generic branch.
3. What user facing string does each handled code map to?

Use this table to categorize `PurchasesErrorCode` values and pick the UX response.

| Code | Meaning | Handling |
|---|---|---|
| `PurchaseCancelledError` | User backed out of the flow | Do nothing. `userCancelled` is also `true`. |
| `ProductAlreadyPurchasedError` | Product already active for the user | Refresh `CustomerInfo` and check entitlements. |
| `PaymentPendingError` | Purchase entered pending state | Show a pending message. Wait for `UpdatedCustomerInfoListener`. |
| `NetworkError` | Request failed due to connectivity | Prompt the user to retry. |
| `StoreProblemError` | Google Play issue | Prompt to retry or update Play Store. |
| `PurchaseNotAllowedError` | Device or account cannot purchase | Show an explanatory message. |
| `IneligibleError` | User not eligible for the offer | Show the base plan instead. |

Exception type decision:

| Call | Exception to catch | `userCancelled` available? |
|---|---|---|
| `awaitPurchase()` | `PurchasesTransactionException` | Yes |
| `awaitRestore()` | `PurchasesException` | No |
| `awaitOfferings()` | `PurchasesException` | No |
| `awaitGetProducts()` | `PurchasesException` | No |
| `awaitCustomerInfo()` | `PurchasesException` | No |

## Phase 3: Execute

### Purchase errors

Check `userCancelled` first and return silently. Then branch on `error.code`.

```kotlin
try {
    val result = Purchases.sharedInstance.awaitPurchase(params)
    handleSuccess(result.customerInfo)
} catch (e: PurchasesTransactionException) {
    if (e.userCancelled) return
    when (e.error.code) {
        PurchasesErrorCode.PaymentPendingError -> showPendingMessage()
        PurchasesErrorCode.ProductAlreadyPurchasedError -> {
            val info = Purchases.sharedInstance.awaitCustomerInfo()
            handleSuccess(info)
        }
        PurchasesErrorCode.NetworkError -> showRetryDialog()
        else -> showGenericError(userFacingMessage(e.error))
    }
}
```

### Non purchase errors

Catch `PurchasesException` and branch on the code. Use offline or cached fallbacks where you have them.

```kotlin
try {
    val offerings = Purchases.sharedInstance.awaitOfferings()
    displayOfferings(offerings)
} catch (e: PurchasesException) {
    when (e.error.code) {
        PurchasesErrorCode.NetworkError -> showOfflineFallback()
        else -> logError(e.error)
    }
}
```

### Map codes to user facing strings

Keep a single mapping function. Never pass `e.error.message` to the UI.

```kotlin
fun userFacingMessage(error: PurchasesError): String = when (error.code) {
    PurchasesErrorCode.PurchaseCancelledError -> ""
    PurchasesErrorCode.NetworkError ->
        "Please check your internet connection and try again."
    PurchasesErrorCode.StoreProblemError ->
        "There was a problem with Google Play. Please try again."
    PurchasesErrorCode.ProductAlreadyPurchasedError ->
        "You already have this subscription."
    PurchasesErrorCode.PaymentPendingError ->
        "Your payment is being processed. We'll notify you when it completes."
    else -> "Something went wrong. Please try again."
}
```

## Checklist

- You picked `PurchasesTransactionException` for `awaitPurchase` and `PurchasesException` elsewhere.
- You checked `userCancelled` before any branching on `error.code`.
- You handled `PaymentPendingError`, `ProductAlreadyPurchasedError`, and `NetworkError` with their specific flows.
- You logged `error.message` and showed a mapped string from `userFacingMessage` to the user.
- You did not add retry loops around SDK calls. Retries are user initiated only.

## References

- [Full chapter](https://www.revenuecat.com/guides/revenuecat-android-sdk/error-handling)

© RevenueCat · MIT · RevenueCat/ai-toolkit

Похожие скиллы

Всё по теме «Мобильная разработка» →
golang-error-handling samber Скилл для идиоматичной обработки ошибок в Go: оборачивание с контекстом, проверка цепочек, структурированное логирование и интеграция с samber/oops. Применяется при создании, оборачивании, инспекции и логировании ошибок. CX Codex +1 43 400установок error-handling-patterns Seth Hobson Скилл помогает проектировать обработку ошибок: исключения, Result-типы, передачу контекста и graceful degradation. Пригодится для API и отладки сбоев. CX Codex 22 957установок error-handling affaan-m Скилл задаёт единые правила обработки ошибок в TypeScript, Python и Go: типизированные исключения, ретраи, circuit breaker, тексты для пользователя. CX Codex +1 4 800установок iii-error-handling iii-hq Скилл учит агента распознавать коды ошибок iii-движка и SDK, различать сетевые сбои от отказов в доступе, определять, когда повторять вызов безопасно. Нужен, если пишешь код на Node, Python, Rust или в браузере с вызовами удалённых функций. CX Codex +1 4 100установок n8n-error-handling czlonkowski Настраивает обработку сбоев в n8n: ветки ошибок, повторные попытки и ответные статусы для вебхуков. Нужен, когда сценарий не должен молча завершаться. CX Codex +1 2 000установок go-error-handling cxuu Скилл учит агента писать надёжную обработку ошибок в Go: выбирать между %w и %v, задавать sentinel-ошибки и не смешивать логирование с возвратом. CX Codex +1 1 300установок

Из того же набора25

rc-setup Проведёт по дашборду RevenueCat и подключению Google Play: приложение, сервисный аккаунт, entitlements, offerings и публичный API-ключ. CX Codex +1 638установок rc-configuring-the-sdk Скилл проводит агента через подключение RevenueCat к Android-приложению: Gradle-зависимость, Purchases.configure, стратегия app user id и уровень логов. CX Codex +1 636установок rc-catalog-management Ведёт каталог Android-товаров между Play Console и панелью RevenueCat: импорт продуктов, привязка к entitlement, сборка офферов. CX Codex +1 627установок rc-subscription-states Скилл для Android-проектов на RevenueCat: подсказывает агенту, как проверять доступ к платному контенту через CustomerInfo и EntitlementInfo. CX Codex +1 623установок rc-revenuecat-api-quick-reference Справочник по Android SDK 10.x и REST API RevenueCat прямо в редакторе: сигнатуры вызовов, структура Offerings, поля CustomerInfo. CX Codex +1 624установок rc-price-changes Помогает провести новую цену подписки в Google Play через RevenueCat, не трогая код приложения. CX Codex +1 618установок rc-understanding-revenuecat Объясняет агенту, как устроен RevenueCat Android SDK 10.x, до того как он напишет хоть строчку кода. Пригодится, если вы переходите с чистого Play Billing. CX Codex +1 617установок rc-cancellations-pauses-winback Показывает в Android-приложении отмену подписки, паузу и возврат клиента. Помогает не гадать, что происходит с доступом. CX Codex +1 612установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой