Repository navigation
Error Codes
클라이언트는 code로만 분기합니다. message는 사람이 읽는 문장이라 언제든 바뀌지만
code는 계약입니다. 정본은
server/internal/platformerr/code.go이고,
OpenAPI 각 응답에도 적혀 있습니다.
TypeScript는 PlatformError.code, GDScript는 콜백의 res["code"]입니다. local이
true면 서버가 아니라 SDK가 만든 판정입니다.
| code | SDK | 뜻 | 대응 |
|---|---|---|---|
network_error |
TS | 서버에 닿지 못함 | 재시도 안내 |
auth_required |
TS·GD | 세션 없이 인증 필요한 호출 | 로그인 |
anonymous_not_allowed |
GD | 익명 세션으로 결제 시도 (서버 왕복 전에 차단) | 로그인 유도 |
purchase_proof_invalid |
TS·GD | proof에 빈 값 (서버 왕복 전에 차단) | 앱 버그 |
auth_state_changed |
GD | refresh 중 sign_in/sign_out이 끼어들어 이전 세대 요청을 끝냄 |
무시하거나 재시도 |
iap_response_invalid |
TS | 결제 응답 envelope 해석 실패 | 재시도 금지. 로그 후 CS |
request_invalid internal
|
TS | 요청 조립 실패 | 앱 버그 |
| code | HTTP | 뜻 | 대응 |
|---|---|---|---|
auth_required |
401 | 토큰 없음 | 로그인 |
auth_invalid |
401 | 자격증명 검증 실패 — 만료된 Firebase 토큰, 잘못된 aud
|
자격증명 재발급 후 signIn
|
auth_forbidden |
403 | 신원은 맞지만 권한 없음 | 앱 로직 점검 |
session_invalid |
401 | 세션 토큰이 손상됨 | 재로그인 |
session_expired |
401 | 세션 만료 | SDK가 refresh로 자동 복구. IAP 경로는 1회 replay |
refresh_invalid |
401 | refresh 토큰 무효 | 재로그인 |
anonymous_not_allowed |
403 | 익명 세션으로 결제 | 로그인 유도 |
account_link_required |
403 |
require_linked_account 앱에서 미연결 세션으로 유료 접근 |
Kakao·Apple 연결 흐름 |
account_link_conflict |
— | 다른 사용자에 이미 연결된 외부 계정 | 사용자에게 안내 |
user_blocked |
— | 운영자가 차단한 계정 | 안내 화면. 우회 시도 금지 |
user_not_found |
— | 매핑 없음 | 재로그인 |
require_app_check가 켜진 앱의 custom token 발급과 계정 삭제 경계에서 납니다.
| code | 뜻 |
|---|---|
app_check_required |
X-Firebase-AppCheck 헤더 없음 |
app_check_invalid |
토큰 검증 실패 |
app_check_replayed |
한 번 쓴 토큰 재사용 |
app_check_app_mismatch |
다른 앱의 토큰 |
| code | 뜻 | 대응 |
|---|---|---|
app_unknown |
appId가 레지스트리에 없음 |
등록 확인 |
app_paused |
kill switch — 앱 전체 정지 (403) | 점검 안내 |
rate_limited |
한도 초과 |
Retry-After 존중 |
| code | 뜻 | 대응 |
|---|---|---|
purchase_proof_invalid |
proof 형식 오류 | 앱 버그 |
platform_invalid platform_mismatch
|
마켓 값이 잘못됐거나 앱에 허용되지 않음 | 앱 버그 |
product_not_allowed |
이 앱의 카탈로그에 없는 상품 | "구매 불가 상품" 안내 |
product_mismatch product_type_mismatch
|
증명의 상품과 요청 불일치 | 앱 버그 |
bundle_mismatch |
앱 번들·패키지 불일치 | 레지스트리 확인 |
purchase_invalid |
마켓이 증명을 인정하지 않음 | 재시도 금지. CS |
purchase_not_found |
마켓에 거래 없음 | CS |
purchase_owned_by_another_user |
다른 사용자가 이미 소유 (불변식 4) | "다른 계정 구매" 안내 |
purchase_replay_mismatch |
같은 증명으로 다른 내용 재요청 | 앱 버그 |
account_binding_missing account_binding_mismatch
|
구매에 계정 참조가 없거나 다른 계정 | 구매 전 accountReferences() 적용 |
transaction_mismatch |
거래 식별자 불일치 | CS |
environment_mismatch |
sandbox/production 어긋남 | 메인테이너 |
catalog_* |
서버 카탈로그 문제 | 메인테이너 |
provider_completion_pending |
마켓 완료 처리 대기 |
completion.action 수행 후 재확인 |
provider_auth_failed provider_unavailable provider_timeout provider_response_invalid
|
마켓 API 장애 | 잠시 후 재시도 — 사용자가 결정 |
| code | 뜻 | 대응 |
|---|---|---|
ads_not_enabled |
앱에 광고 기능 없음 | 광고 경로 숨김 |
ads_suppressed |
운영자 또는 ad_free로 억제 |
광고 숨김 |
ad_placement_invalid ad_reward_invalid ad_unit_mismatch
|
레지스트리 placement와 불일치 | 앱 버그 |
ad_daily_limit |
일일 한도 | 안내 |
ad_cooldown |
cooldown 중 | 남은 시간 안내 |
ad_claim_not_found ad_claim_expired
|
claim 없음·만료 | 새 claim |
ad_claim_state_invalid ad_claim_assurance_invalid
|
허용되지 않는 상태 전이 | 어댑터 사용 권장 |
ad_claim_ownership_mismatch |
다른 세션의 claim | 앱 버그 |
ad_claim_replay_mismatch ad_claim_transaction_replayed
|
멱등 키 충돌 | 새 requestId
|
admob_ssv_* |
SSV 서명 검증 실패 | 클라이언트 확인 경로 없음. 보상 지급 금지 |
| code | 뜻 |
|---|---|
config_unavailable |
설정 조회 실패 — SDK가 열린 기본값으로 대체하므로 앱에는 거의 안 보임 |
content_not_enabled content_unavailable content_locked content_ticket_empty … |
운글 전용 private 콘텐츠 계약 |
request_invalid, request_too_large(64KiB 초과), content_type_invalid,
method_not_allowed. 전부 앱 버그이거나 SDK 버전 불일치입니다. 허용 필드 외 어떤
키도 400입니다.
sandbox_reset_*, refund_review_*, event_*, notification_invalid,
package_mismatch, partial_refund_unsupported, operator_replay_mismatch,
completion_*, ledger_state_invalid, runtime_config_invalid,
secret_config_invalid, platform_unavailable은 웹훅과 Admin API에서 납니다.
클라이언트 SDK가 볼 일은 없고, 보이면 메인테이너에게 알립니다.
구현과 API 계약의 정본은 seorilabs/platform 저장소입니다.