gpc-troubleshooting
Unified debugging guide for all GPC errors, exit codes, and common issues.
When to use
- GPC command fails with an error code
gpc doctor reports issues
- CI pipeline fails with a GPC step
- Unexpected behavior or output
- Need to interpret exit codes
- Need to enable verbose/debug output
Inputs required
- Error message or exit code — what GPC reported
- Command that failed — the full command that was run
- Environment — local vs CI, OS, Node.js version
Procedure
0. Quick diagnosis
# Check GPC health
gpc doctor
# Get version info
gpc --version
# Run failing command with verbose output
GPC_DEBUG=1 gpc <failing-command>
# Get error as JSON for parsing (also: --output csv, --output tsv since v0.9.68)
gpc <failing-command> --json
Read: references/exit-codes.md for the complete exit code reference.
1. Exit codes
| Code |
Category |
Meaning |
| 0 |
Success |
Command completed successfully |
| 1 |
Config |
Configuration error (missing .gpcrc.json, invalid fields) |
| 2 |
Usage |
Invalid arguments or flags |
| 3 |
Auth |
Authentication failure (expired token, invalid key, no credentials) |
| 4 |
API |
Google Play API error (403, 404, 408, 409, rate limit) |
| 5 |
Network |
Connection failure, DNS error, timeout |
| 6 |
Threshold |
Vitals threshold breached (used in CI gating) |
| 10 |
Plugin |
Plugin permission validation error |
2. Authentication errors (exit code 3)
Read: references/error-catalog.md for the full error catalog.
| Error |
Cause |
Fix |
AUTH_FAILED |
Invalid or corrupted credentials |
Re-run gpc auth login --service-account <key.json> |
AUTH_EXPIRED |
Token expired and refresh failed |
Re-authenticate; check network/proxy |
AUTH_NO_CREDENTIALS |
No auth configured |
Run gpc auth login or set GPC_SERVICE_ACCOUNT |
AUTH_INVALID_KEY |
Malformed service account JSON |
Re-download key from Google Cloud Console |
AUTH_KEYCHAIN_ERROR |
OS keychain access denied |
Grant keychain access or use env var auth |
# Check current auth status
gpc auth status
# Re-authenticate
gpc auth login --service-account ~/path/to/key.json
# Bypass keychain with env var
export GPC_SERVICE_ACCOUNT=$(cat ~/path/to/key.json)
3. API errors (exit code 4)
| Error |
HTTP |
Cause |
Fix |
API_FORBIDDEN |
403 |
Insufficient permissions |
Grant required roles in Play Console |
API_NOT_FOUND |
404 |
App, track, or resource doesn't exist |
Verify package name, track name, or resource ID |
API_CONFLICT |
409 |
Edit already in progress |
Wait and retry; another edit may be open |
API_RATE_LIMITED |
429 |
Too many requests |
GPC auto-retries; increase GPC_BASE_DELAY |
API_REQUEST_TIMEOUT |
408 |
Request timed out |
GPC auto-retries with exponential backoff |
API_SERVER_ERROR |
5xx |
Google server issue |
Retry later; check Google status dashboard |
EDIT_CONFLICT |
409 |
Concurrent edit from another tool/user |
Only one edit at a time; check if Fastlane or Play Console has an open edit |
API_DUPLICATE_VERSION_CODE |
409 |
Version code already uploaded |
Increment versionCode in build.gradle and rebuild |
API_VERSION_CODE_TOO_LOW |
400 |
Version code lower than current |
Version code must increase per track |
API_PACKAGE_NAME_MISMATCH |
400 |
applicationId doesn't match target app |
Verify applicationId matches target app |
API_APP_NOT_FOUND |
404 |
App not in developer account |
Verify package name and developer account |
API_INSUFFICIENT_PERMISSIONS |
403 |
Service account missing permissions |
Grant required roles in Play Console → Settings → API access |
API_DECLARATION_REQUIRED |
403 |
A Play Console "App content" declaration is incomplete |
Complete it under Policy > App content. Not a permissions problem; changing roles will not help |
API_ALREADY_EXISTS |
409 |
The resource you tried to create is already there |
Use the matching update command instead of create (e.g. gpc otp offers update) |
API_ENDPOINT_RETIRED |
404 |
Google removed the endpoint from its published API |
Not fixable from the CLI -- do the task in Play Console. Currently affects gpc games ... set-icon |
API_CHANGES_NOT_SENT_FOR_REVIEW |
400/403 |
App has rejected update, requires review flag |
Add --changes-not-sent-for-review flag to the command |
API_CHANGES_ALREADY_IN_REVIEW |
400 |
Changes already in review, new commit would silently cancel |
Use --error-if-in-review to prevent silent cancellation |
API_EDIT_EXPIRED |
410 |
The open edit session has expired (edits expire after ~30 minutes of inactivity) |
GPC now includes a clear API_EDIT_EXPIRED message with a suggestion to retry the command. The command will automatically create a fresh edit on retry. |
API_ROLLOUT_DECREASE_FORBIDDEN |
400 |
Staged rollout percentage can only be increased, not decreased |
To stop a rollout, use gpc releases rollout halt --track production. To continue, use gpc releases rollout increase with a higher percentage. |
# Check if an edit is stuck
gpc apps list --json
# API errors include suggestion field
gpc releases upload app.aab --track beta --json 2>&1 | jq '.error'
4. Network errors (exit code 5)
| Error |
Cause |
Fix |
NETWORK_ERROR |
Connection failed |
Check internet; check proxy settings |
NETWORK_TIMEOUT |
Request timed out |
Increase GPC_TIMEOUT (default 30000ms) |
NETWORK_DNS |
DNS resolution failed |
Check DNS settings; try Google DNS (8.8.8.8) |
NETWORK_SSL |
SSL/TLS handshake failed |
Set GPC_CA_CERT for custom CA; check proxy |
# Increase timeout for large uploads
export GPC_TIMEOUT=120000
# Configure retry behavior
export GPC_MAX_RETRIES=5
export GPC_BASE_DELAY=2000
export GPC_MAX_DELAY=30000
# Corporate proxy
export HTTPS_PROXY=http://proxy.corp:8080
# Custom CA certificate
export GPC_CA_CERT=/path/to/ca-cert.pem
5. Configuration errors (exit code 1)
| Error |
Cause |
Fix |
CONFIG_MISSING |
No .gpcrc.json or env vars |
Run gpc setup (v0.9.68+) or gpc config init |
CONFIG_INVALID |
Malformed .gpcrc.json |
Validate JSON syntax |
CONFIG_INVALID_JSON |
Config file contains syntax errors (v0.9.80+) |
Run cat <file> | python3 -m json.tool to find the error |
CONFIG_INVALID_KEY |
Key is empty, malformed, or a reserved name (v0.9.80+) |
Use a valid alphanumeric profile/key name |
CONFIG_APP_MISSING |
No app specified |
Set with gpc config set app or --app flag |
Config precedence fix (v0.9.81+): Before v0.9.81, an active profile would silently win over GPC_SERVICE_ACCOUNT/GPC_APP env vars and the --service-account/--app flags. This was a bug. Since v0.9.81, the documented precedence is enforced: flags override env vars, env vars override the active profile, the active profile overrides defaults. If env vars appear to be ignored, check whether an active profile is set with gpc config list and either update or deactivate it.
# Initialize config
gpc config init
# Set required values
gpc config set app com.example.app
# Check current config
gpc config list
6. Upload and release errors
| Error |
Cause |
Fix |
INVALID_BUNDLE |
AAB is corrupted or wrong format |
Rebuild the AAB; run gpc validate first |
VERSION_CODE_CONFLICT |
Version code already used |
Increment versionCode in build.gradle |
RELEASE_NOT_FOUND |
No release on the specified track |
Check track name; use gpc releases list --track <track> |
ROLLOUT_INVALID |
Invalid rollout percentage |
Use 0-100 (not 0.0-1.0); use --rollout 10 not --rollout 0.1 |
PROMOTE_NO_SOURCE |
Source track has no release to promote |
Upload to source track first |
UPLOAD_CHUNK_FAILED |
Chunk could not be sent after retries |
Check network; increase GPC_MAX_RETRIES or GPC_UPLOAD_TIMEOUT |
UPLOAD_NO_COMPLETION |
All bytes sent but no completion response |
Retry upload; check GPC_UPLOAD_TIMEOUT |
UPLOAD_INITIATE_FAILED |
Session initiation failed |
Check auth and permissions; retry |
UPLOAD_NO_SESSION_URI |
No Location header in initiation response |
API error; retry or check service account permissions |
UPLOAD_SESSION_NOT_FOUND |
Session expired (404) |
Start a new upload session |
UPLOAD_SESSION_EXPIRED |
Session gone (410) |
Start a new upload session |
UPLOAD_INVALID_CHUNK_SIZE |
Chunk size not multiple of 256 KB |
Set GPC_UPLOAD_CHUNK_SIZE to a multiple of 262144 (256 KB) |
EDIT_VALIDATE_FAILED |
Transient validate/commit failure after upload |
Auto-retried with multi-retry guard (15s, 30s, 45s) since v0.9.77; if persistent, check bundle status |
REVIEW_SKIPPED |
Internal track commit completed without entering Google review queue |
Expected behavior. The internal track does not require review. GPC sets reviewSkipped: true in structured JSON output (v0.9.79+) to confirm the commit went through immediately. |
# Validate before uploading
gpc validate app.aab
# Check existing releases
gpc releases list --track internal
gpc releases list --track beta
# Preview upload
gpc releases upload app.aab --track beta --dry-run
Commit rejection: reviewPending structured output (v0.9.79+)
When edits.commit is rejected because Google requires review, the --json output includes a structured result instead of a plain error:
{
"reviewPending": true,
"nextStep": "Your changes are under Google review. Check Play Console for status or use --changes-not-sent-for-review to bypass review for non-reviewed tracks."
}
CI pipelines can key on reviewPending === true to decide whether to wait, notify, or exit. The nextStep field always contains human-readable guidance on what to do next.
7. Vitals threshold breach (exit code 6)
Exit code 6 is not an error — it's an intentional signal that a vitals metric exceeded the threshold. Used for CI gating.
# This exits 6 if crash rate > 2.0%
gpc vitals crashes --threshold 2.0
# Check the actual value
gpc vitals crashes --json | jq '.crashRate'
# In CI, use exit code to gate promotion
gpc vitals crashes --threshold 1.5 && gpc releases promote --from beta --to production
7a. Order refund review errors (exit code 2, v0.9.96+)
| Code |
Meaning |
Fix |
ORDER_REVIEW_REFUND_INVALID |
gpc purchases orders review-refund was given invalid input: --sample-content-provided unanswered, --consumption-percent outside 0-100, or --usage-events-file that is not a JSON array of objects |
Pass exactly one of --sample-content-provided / --no-sample-content-provided, use a plain decimal such as --consumption-percent 45.2, and make the file an array like [{ "consumptionTime": "2026-08-30T10:15:00Z" }] |
Rejected locally before anything is sent, so a bad command never burns part of Google's 24-hour response window. An empty or whitespace-only --consumption-percent counts as not provided rather than as 0%.
8. Plugin errors (exit code 10)
| Error |
Cause |
Fix |
PLUGIN_INVALID_PERMISSION |
Third-party plugin declares unknown permission |
Check valid permissions in plugin-sdk docs |
PLUGIN_PERMISSIONS_REQUIRED |
Third-party plugin declares no gpc.permissions (v0.9.94+) |
Ask the author to declare the hooks it uses, then approve it again |
PLUGIN_IDENTITY_MISMATCH |
Specifier claims a first-party package but resolves elsewhere (v0.9.94+) |
Remove the npm alias or local replacement for @gpc-cli/plugin-ci |
| Plugin not loading |
Not in config or not approved |
Add to plugins and approvedPlugins in .gpcrc.json |
| Plugin error in hook |
Bug in plugin handler |
Check plugin logs; onError/API hooks swallow errors |
Changelog generation errors (v0.9.61+)
| Code |
Meaning |
Fix |
CHANGELOG_NO_TAG |
No v* git tag found, --from not passed |
Create a tag (git tag v0.0.1) or pass --from <ref> |
CHANGELOG_BAD_REF |
--from or --to ref doesn't exist |
Run git rev-parse --verify <ref> to check |
CHANGELOG_LOCALES_REQUIRED |
--target play-store passed without --locales (v0.9.62+) |
Pass --locales en-US,fr-FR or --locales auto |
CHANGELOG_LOCALES_INVALID |
One or more --locales are not valid BCP 47 (v0.9.62+) |
Use Play Store-supported codes like en-US, fr-FR, de-DE |
CHANGELOG_LOCALES_AUTO_NO_APP |
--locales auto without an authenticated client + app (v0.9.62+) |
Pass --app <package> or set config.app, check credentials |
CHANGELOG_FETCH_FAILED |
GitHub API unreachable or returned an error (v0.9.80+) |
Check network; view changelog at the docs site |
CHANGELOG_VERSION_NOT_FOUND |
Requested version not found in GitHub releases (v0.9.80+) |
Run gpc changelog --limit 10 to see available versions |
WATCH_WEBHOOK_FAILED |
Webhook endpoint returned non-2xx (v0.9.80+) |
Check the webhook URL and server status |
CHANGELOG_LOCALES_EMPTY |
--locales auto returned zero locales (v0.9.62+) |
Create at least one Play Store listing, or pass explicit --locales |
RELEASE_NO_DRAFT |
--apply found no draft release on the target track (v0.9.64+) |
Create a draft release first (gpc releases upload --status draft) |
BUNDLE_PROCESSING_TIMEOUT |
AAB upload completed but bundle not processed within ~86s (v0.9.64+, extended v0.9.77) |
Retry the upload, or use --status draft and commit later; if persistent, check bundle size and Google's server status |
Bulk report errors (v0.9.93+)
gpc reports list and gpc reports download stats|financial read Play's monthly bulk-report CSVs from the Cloud Storage bucket linked to the developer account (pubsite_prod_<developerId>). Before v0.9.93 these commands only printed guidance; they now do real network work, with their own error codes.
| Code |
Exit |
Meaning |
Fix |
REPORT_ACCESS_DENIED |
4 |
Credential is valid but not authorized to read the reports bucket |
Play Console -> Users and permissions -> the service account -> Account permissions -> enable "View app information and download bulk reports (read-only)", wait a few minutes, then retry |
REPORT_AUTH_REJECTED |
3 |
Google rejected the token itself (HTTP 401) |
Check the key with gpc auth status, verify the system clock, then gpc auth clear-cache and retry |
REPORT_BUCKET_UNKNOWN |
2 |
No bucket configured and no developer id to derive one from |
Set developerId / GPC_DEVELOPER_ID, or pass --bucket / GPC_REPORTS_BUCKET / reports.bucket |
REPORT_BUCKET_INVALID |
2 |
The configured bucket name is not a valid GCS bucket name |
Copy the exact Cloud Storage URI from Play Console -> Download reports (a gs:// URI is accepted and reduced to the bucket name) |
REPORT_BUCKET_NOT_FOUND |
4 |
The bucket does not exist or is invisible to this account |
Confirm the name; the default is pubsite_prod_<developerId> |
REPORT_OBJECT_NOT_FOUND |
4 |
No object matched the type / month / dimension |
The error lists available dimensions or months; a month is only published after it ends |
REPORT_LIST_FAILED |
4 |
The bucket listing call failed |
Retry; check network and gpc doctor |
REPORT_DOWNLOAD_FAILED |
4 |
The object fetch failed |
Retry; check network |
REPORT_DECODE_FAILED |
4 |
The object could not be gunzipped or decoded from UTF-16 |
Retry the download; if it persists, save the raw object with --output-file and report it |
REPORT_ARCHIVE_UNREADABLE |
4 |
A financial ZIP archive could not be read |
Save it raw with --output-file report.zip and open it locally |
REPORT_MULTIPLE_ENTRIES |
2 |
A financial archive holds several CSVs, so there is nothing single to print |
Use --output-file report.zip to save the archive, or --json to inline every entry |
INVALID_REPORT_DIMENSION |
2 |
--dimension is not one of the supported values |
Use overview, country, language, os_version, device, app_version, carrier, or traffic_source (reviews reports have no dimension) |
MISSING_REQUIRED_OPTION |
2 |
A required flag such as --month or --type was omitted |
Check the synopsis: stats downloads need --month and --type |
INVALID_LIMIT |
2 |
--limit is not a positive integer |
Pass a positive whole number |
gpc doctor includes a reports-bucket probe: it warns when the grant is missing (403/401) or the bucket name is wrong (404), so it is the fastest way to confirm setup before debugging a command.
9. Debug mode
Enable verbose output for any command:
# Debug environment variable
GPC_DEBUG=1 gpc releases upload app.aab --track beta
# JSON output for machine parsing
gpc releases upload app.aab --track beta --json
# Combine for maximum detail
GPC_DEBUG=1 gpc releases upload app.aab --track beta --json 2>debug.log
10. Retryable HTTP status codes
GPC automatically retries the following HTTP status codes with exponential backoff:
- 408 — Request Timeout
- 429 — Too Many Requests (rate limited)
- 5xx — Server errors (500, 502, 503, etc.)
Configure retry behavior:
export GPC_MAX_RETRIES=5 # Default: 5
export GPC_BASE_DELAY=1000 # Initial delay in ms
export GPC_MAX_DELAY=15000 # Max delay in ms
export GPC_UPLOAD_TIMEOUT=300000 # Upload timeout in ms (5 min)
Verification
gpc doctor passes all checks
- Failing command now succeeds or shows a clear, actionable error
- Exit code matches the expected category
--json output includes error.code, error.message, and error.suggestion
Failure modes / debugging
| Symptom |
Likely Cause |
Fix |
gpc doctor fails on auth |
Credentials not configured |
Run gpc setup (v0.9.68+) or gpc auth login |
gpc doctor fails on API |
Service account lacks API access |
Enable Google Play Developer API in GCP |
gpc doctor quota warning |
>80% of daily or per-minute API quota used |
Reduce request frequency or request quota increase from Google (v0.9.71+) |
gpc doctor plugin error |
A configured plugin fails to load |
Check plugin package version, reinstall, or remove from config (v0.9.71+) |
gpc doctor --verify mismatch |
Local keystore differs from Play signing cert |
Register local key in Play Console or use Play App Signing (v0.9.75+) |
| All commands timeout |
Network/proxy issue |
Check HTTPS_PROXY, GPC_CA_CERT, GPC_TIMEOUT |
| Commands work locally, fail in CI |
Missing env vars in CI |
Set GPC_SERVICE_ACCOUNT and GPC_APP in CI secrets; run gpc setup --auto (v0.9.68+) |
Env vars GPC_SERVICE_ACCOUNT / GPC_APP seem to be ignored |
Active profile overriding env vars (pre-v0.9.81 bug) |
Upgrade to v0.9.81+. Check active profile with gpc config list; env vars and flags now correctly override the profile. |
npm install -g @gpc-cli/cli fails with EUNSUPPORTEDPROTOCOL |
workspace:* specifiers leaked into published manifests (v0.9.77-v0.9.83) |
Reinstall on v0.9.84+ or v0.9.85+: npm install -g @gpc-cli/cli@latest. Fixed in v0.9.84 (cli+core) and fully resolved in v0.9.85 (api package re-published). |
gpc doctor warns on reports-bucket |
Service account lacks the bulk-reports grant, or the bucket name is wrong |
Enable "View app information and download bulk reports (read-only)" in Play Console, or set the exact bucket with --bucket / GPC_REPORTS_BUCKET (v0.9.93+) |
| Reports still denied right after granting the permission |
Grant has not propagated, or a cached token predates it |
Wait a few minutes, run gpc auth clear-cache, then retry (v0.9.93+) |
JSON output has no suggestion |
Unexpected error type |
File a bug — all errors should have suggestions |
Related skills
- gpc-setup — initial auth and config setup
- gpc-ci-integration — CI-specific troubleshooting
- gpc-vitals-monitoring — understanding threshold breaches
- gpc-plugin-development — debugging plugin issues
1---2name: gpc-troubleshooting3description: Use when debugging GPC errors, failures, or unexpected behavior. Make sure to use this skill whenever the user mentions gpc error, gpc failing, exit code, AUTH_FAILED, API_FORBIDDEN, NETWORK_ERROR, CONFIG_MISSING, EDIT_CONFLICT, upload failed, permission denied, timeout, rate limit, gpc doctor failing, unexpected exit code, command not working, GPC crash, debug GPC, verbose output, --json error, threshold breach, REPORT_ACCESS_DENIED, REPORT_BUCKET_NOT_FOUND, reports bucket access, bulk reports permission denied, API_DECLARATION_REQUIRED, App content declaration, foreground service declaration, API_ALREADY_EXISTS, API_ENDPOINT_RETIRED, ORDER_REVIEW_REFUND_INVALID, PLUGIN_PERMISSIONS_REQUIRED, PLUGIN_IDENTITY_MISMATCH — even if they don't explicitly say 'troubleshoot.' Also trigger when someone encounters any GPC error they don't understand, when gpc doctor reports issues, when CI pipelines fail with GPC commands, or when they need to interpret exit codes. For auth-specific setup issues, see gpc-setup. For CI-4---56# gpc-troubleshooting78Unified debugging guide for all GPC errors, exit codes, and common issues.910## When to use1112- GPC command fails with an error code13- `gpc doctor` reports issues14- CI pipeline fails with a GPC step15- Unexpected behavior or output16- Need to interpret exit codes17- Need to enable verbose/debug output1819## Inputs required2021- **Error message or exit code** — what GPC reported22- **Command that failed** — the full command that was run23- **Environment** — local vs CI, OS, Node.js version2425## Procedure2627### 0. Quick diagnosis2829```bash30# Check GPC health31gpc doctor3233# Get version info34gpc --version3536# Run failing command with verbose output37GPC_DEBUG=1 gpc <failing-command>3839# Get error as JSON for parsing (also: --output csv, --output tsv since v0.9.68)40gpc <failing-command> --json41```4243`Read:` `references/exit-codes.md` for the complete exit code reference.4445### 1. Exit codes4647| Code | Category | Meaning |48|------|----------|---------|49| 0 | Success | Command completed successfully |50| 1 | Config | Configuration error (missing .gpcrc.json, invalid fields) |51| 2 | Usage | Invalid arguments or flags |52| 3 | Auth | Authentication failure (expired token, invalid key, no credentials) |53| 4 | API | Google Play API error (403, 404, 408, 409, rate limit) |54| 5 | Network | Connection failure, DNS error, timeout |55| 6 | Threshold | Vitals threshold breached (used in CI gating) |56| 10 | Plugin | Plugin permission validation error |5758### 2. Authentication errors (exit code 3)5960`Read:` `references/error-catalog.md` for the full error catalog.6162| Error | Cause | Fix |63|-------|-------|-----|64| `AUTH_FAILED` | Invalid or corrupted credentials | Re-run `gpc auth login --service-account <key.json>` |65| `AUTH_EXPIRED` | Token expired and refresh failed | Re-authenticate; check network/proxy |66| `AUTH_NO_CREDENTIALS` | No auth configured | Run `gpc auth login` or set `GPC_SERVICE_ACCOUNT` |67| `AUTH_INVALID_KEY` | Malformed service account JSON | Re-download key from Google Cloud Console |68| `AUTH_KEYCHAIN_ERROR` | OS keychain access denied | Grant keychain access or use env var auth |6970```bash71# Check current auth status72gpc auth status7374# Re-authenticate75gpc auth login --service-account ~/path/to/key.json7677# Bypass keychain with env var78export GPC_SERVICE_ACCOUNT=$(cat ~/path/to/key.json)79```8081### 3. API errors (exit code 4)8283| Error | HTTP | Cause | Fix |84|-------|------|-------|-----|85| `API_FORBIDDEN` | 403 | Insufficient permissions | Grant required roles in Play Console |86| `API_NOT_FOUND` | 404 | App, track, or resource doesn't exist | Verify package name, track name, or resource ID |87| `API_CONFLICT` | 409 | Edit already in progress | Wait and retry; another edit may be open |88| `API_RATE_LIMITED` | 429 | Too many requests | GPC auto-retries; increase `GPC_BASE_DELAY` |89| `API_REQUEST_TIMEOUT` | 408 | Request timed out | GPC auto-retries with exponential backoff |90| `API_SERVER_ERROR` | 5xx | Google server issue | Retry later; check Google status dashboard |91| `EDIT_CONFLICT` | 409 | Concurrent edit from another tool/user | Only one edit at a time; check if Fastlane or Play Console has an open edit |92| `API_DUPLICATE_VERSION_CODE` | 409 | Version code already uploaded | Increment versionCode in build.gradle and rebuild |93| `API_VERSION_CODE_TOO_LOW` | 400 | Version code lower than current | Version code must increase per track |94| `API_PACKAGE_NAME_MISMATCH` | 400 | applicationId doesn't match target app | Verify applicationId matches target app |95| `API_APP_NOT_FOUND` | 404 | App not in developer account | Verify package name and developer account |96| `API_INSUFFICIENT_PERMISSIONS` | 403 | Service account missing permissions | Grant required roles in Play Console → Settings → API access |97| `API_DECLARATION_REQUIRED` | 403 | A Play Console "App content" declaration is incomplete | Complete it under Policy > App content. Not a permissions problem; changing roles will not help |98| `API_ALREADY_EXISTS` | 409 | The resource you tried to create is already there | Use the matching `update` command instead of `create` (e.g. `gpc otp offers update`) |99| `API_ENDPOINT_RETIRED` | 404 | Google removed the endpoint from its published API | Not fixable from the CLI -- do the task in Play Console. Currently affects `gpc games ... set-icon` |100| `API_CHANGES_NOT_SENT_FOR_REVIEW` | 400/403 | App has rejected update, requires review flag | Add `--changes-not-sent-for-review` flag to the command |101| `API_CHANGES_ALREADY_IN_REVIEW` | 400 | Changes already in review, new commit would silently cancel | Use `--error-if-in-review` to prevent silent cancellation |102| `API_EDIT_EXPIRED` | 410 | The open edit session has expired (edits expire after ~30 minutes of inactivity) | GPC now includes a clear `API_EDIT_EXPIRED` message with a suggestion to retry the command. The command will automatically create a fresh edit on retry. |103| `API_ROLLOUT_DECREASE_FORBIDDEN` | 400 | Staged rollout percentage can only be increased, not decreased | To stop a rollout, use `gpc releases rollout halt --track production`. To continue, use `gpc releases rollout increase` with a higher percentage. |104105```bash106# Check if an edit is stuck107gpc apps list --json108109# API errors include suggestion field110gpc releases upload app.aab --track beta --json 2>&1 | jq '.error'111```112113### 4. Network errors (exit code 5)114115| Error | Cause | Fix |116|-------|-------|-----|117| `NETWORK_ERROR` | Connection failed | Check internet; check proxy settings |118| `NETWORK_TIMEOUT` | Request timed out | Increase `GPC_TIMEOUT` (default 30000ms) |119| `NETWORK_DNS` | DNS resolution failed | Check DNS settings; try Google DNS (8.8.8.8) |120| `NETWORK_SSL` | SSL/TLS handshake failed | Set `GPC_CA_CERT` for custom CA; check proxy |121122```bash123# Increase timeout for large uploads124export GPC_TIMEOUT=120000125126# Configure retry behavior127export GPC_MAX_RETRIES=5128export GPC_BASE_DELAY=2000129export GPC_MAX_DELAY=30000130131# Corporate proxy132export HTTPS_PROXY=http://proxy.corp:8080133134# Custom CA certificate135export GPC_CA_CERT=/path/to/ca-cert.pem136```137138### 5. Configuration errors (exit code 1)139140| Error | Cause | Fix |141|-------|-------|-----|142| `CONFIG_MISSING` | No .gpcrc.json or env vars | Run `gpc setup` (v0.9.68+) or `gpc config init` |143| `CONFIG_INVALID` | Malformed .gpcrc.json | Validate JSON syntax |144| `CONFIG_INVALID_JSON` | Config file contains syntax errors (v0.9.80+) | Run `cat <file> \| python3 -m json.tool` to find the error |145| `CONFIG_INVALID_KEY` | Key is empty, malformed, or a reserved name (v0.9.80+) | Use a valid alphanumeric profile/key name |146| `CONFIG_APP_MISSING` | No app specified | Set with `gpc config set app` or `--app` flag |147148**Config precedence fix (v0.9.81+):** Before v0.9.81, an active profile would silently win over `GPC_SERVICE_ACCOUNT`/`GPC_APP` env vars and the `--service-account`/`--app` flags. This was a bug. Since v0.9.81, the documented precedence is enforced: flags override env vars, env vars override the active profile, the active profile overrides defaults. If env vars appear to be ignored, check whether an active profile is set with `gpc config list` and either update or deactivate it.149150```bash151# Initialize config152gpc config init153154# Set required values155gpc config set app com.example.app156157# Check current config158gpc config list159```160161### 6. Upload and release errors162163| Error | Cause | Fix |164|-------|-------|-----|165| `INVALID_BUNDLE` | AAB is corrupted or wrong format | Rebuild the AAB; run `gpc validate` first |166| `VERSION_CODE_CONFLICT` | Version code already used | Increment versionCode in build.gradle |167| `RELEASE_NOT_FOUND` | No release on the specified track | Check track name; use `gpc releases list --track <track>` |168| `ROLLOUT_INVALID` | Invalid rollout percentage | Use 0-100 (not 0.0-1.0); use `--rollout 10` not `--rollout 0.1` |169| `PROMOTE_NO_SOURCE` | Source track has no release to promote | Upload to source track first |170| `UPLOAD_CHUNK_FAILED` | Chunk could not be sent after retries | Check network; increase `GPC_MAX_RETRIES` or `GPC_UPLOAD_TIMEOUT` |171| `UPLOAD_NO_COMPLETION` | All bytes sent but no completion response | Retry upload; check `GPC_UPLOAD_TIMEOUT` |172| `UPLOAD_INITIATE_FAILED` | Session initiation failed | Check auth and permissions; retry |173| `UPLOAD_NO_SESSION_URI` | No Location header in initiation response | API error; retry or check service account permissions |174| `UPLOAD_SESSION_NOT_FOUND` | Session expired (404) | Start a new upload session |175| `UPLOAD_SESSION_EXPIRED` | Session gone (410) | Start a new upload session |176| `UPLOAD_INVALID_CHUNK_SIZE` | Chunk size not multiple of 256 KB | Set `GPC_UPLOAD_CHUNK_SIZE` to a multiple of 262144 (256 KB) |177| `EDIT_VALIDATE_FAILED` | Transient validate/commit failure after upload | Auto-retried with multi-retry guard (15s, 30s, 45s) since v0.9.77; if persistent, check bundle status |178| `REVIEW_SKIPPED` | Internal track commit completed without entering Google review queue | Expected behavior. The `internal` track does not require review. GPC sets `reviewSkipped: true` in structured JSON output (v0.9.79+) to confirm the commit went through immediately. |179180```bash181# Validate before uploading182gpc validate app.aab183184# Check existing releases185gpc releases list --track internal186gpc releases list --track beta187188# Preview upload189gpc releases upload app.aab --track beta --dry-run190```191192#### Commit rejection: reviewPending structured output (v0.9.79+)193194When `edits.commit` is rejected because Google requires review, the `--json` output includes a structured result instead of a plain error:195196```json197{198 "reviewPending": true,199 "nextStep": "Your changes are under Google review. Check Play Console for status or use --changes-not-sent-for-review to bypass review for non-reviewed tracks."200}201```202203CI pipelines can key on `reviewPending === true` to decide whether to wait, notify, or exit. The `nextStep` field always contains human-readable guidance on what to do next.204205### 7. Vitals threshold breach (exit code 6)206207Exit code 6 is **not an error** — it's an intentional signal that a vitals metric exceeded the threshold. Used for CI gating.208209```bash210# This exits 6 if crash rate > 2.0%211gpc vitals crashes --threshold 2.0212213# Check the actual value214gpc vitals crashes --json | jq '.crashRate'215216# In CI, use exit code to gate promotion217gpc vitals crashes --threshold 1.5 && gpc releases promote --from beta --to production218```219220### 7a. Order refund review errors (exit code 2, v0.9.96+)221222| Code | Meaning | Fix |223|------|---------|-----|224| `ORDER_REVIEW_REFUND_INVALID` | `gpc purchases orders review-refund` was given invalid input: `--sample-content-provided` unanswered, `--consumption-percent` outside 0-100, or `--usage-events-file` that is not a JSON array of objects | Pass exactly one of `--sample-content-provided` / `--no-sample-content-provided`, use a plain decimal such as `--consumption-percent 45.2`, and make the file an array like `[{ "consumptionTime": "2026-08-30T10:15:00Z" }]` |225226Rejected locally before anything is sent, so a bad command never burns part of Google's 24-hour response window. An empty or whitespace-only `--consumption-percent` counts as not provided rather than as 0%.227228### 8. Plugin errors (exit code 10)229230| Error | Cause | Fix |231|-------|-------|-----|232| `PLUGIN_INVALID_PERMISSION` | Third-party plugin declares unknown permission | Check valid permissions in plugin-sdk docs |233| `PLUGIN_PERMISSIONS_REQUIRED` | Third-party plugin declares no `gpc.permissions` (v0.9.94+) | Ask the author to declare the hooks it uses, then approve it again |234| `PLUGIN_IDENTITY_MISMATCH` | Specifier claims a first-party package but resolves elsewhere (v0.9.94+) | Remove the npm alias or local replacement for `@gpc-cli/plugin-ci` |235| Plugin not loading | Not in config or not approved | Add to `plugins` and `approvedPlugins` in .gpcrc.json |236| Plugin error in hook | Bug in plugin handler | Check plugin logs; `onError`/API hooks swallow errors |237238### Changelog generation errors (v0.9.61+)239240| Code | Meaning | Fix |241|----------------------------------|--------------------------------------------------------------|--------------------------------------------------------------|242| `CHANGELOG_NO_TAG` | No `v*` git tag found, `--from` not passed | Create a tag (`git tag v0.0.1`) or pass `--from <ref>` |243| `CHANGELOG_BAD_REF` | `--from` or `--to` ref doesn't exist | Run `git rev-parse --verify <ref>` to check |244| `CHANGELOG_LOCALES_REQUIRED` | `--target play-store` passed without `--locales` (v0.9.62+) | Pass `--locales en-US,fr-FR` or `--locales auto` |245| `CHANGELOG_LOCALES_INVALID` | One or more `--locales` are not valid BCP 47 (v0.9.62+) | Use Play Store-supported codes like `en-US`, `fr-FR`, `de-DE` |246| `CHANGELOG_LOCALES_AUTO_NO_APP` | `--locales auto` without an authenticated client + app (v0.9.62+) | Pass `--app <package>` or set config.app, check credentials |247| `CHANGELOG_FETCH_FAILED` | GitHub API unreachable or returned an error (v0.9.80+) | Check network; view changelog at the docs site |248| `CHANGELOG_VERSION_NOT_FOUND` | Requested version not found in GitHub releases (v0.9.80+) | Run `gpc changelog --limit 10` to see available versions |249| `WATCH_WEBHOOK_FAILED` | Webhook endpoint returned non-2xx (v0.9.80+) | Check the webhook URL and server status |250| `CHANGELOG_LOCALES_EMPTY` | `--locales auto` returned zero locales (v0.9.62+) | Create at least one Play Store listing, or pass explicit `--locales` |251| `RELEASE_NO_DRAFT` | `--apply` found no draft release on the target track (v0.9.64+) | Create a draft release first (`gpc releases upload --status draft`) |252| `BUNDLE_PROCESSING_TIMEOUT` | AAB upload completed but bundle not processed within ~86s (v0.9.64+, extended v0.9.77) | Retry the upload, or use `--status draft` and commit later; if persistent, check bundle size and Google's server status |253254### Bulk report errors (v0.9.93+)255256`gpc reports list` and `gpc reports download stats|financial` read Play's monthly bulk-report CSVs from the Cloud Storage bucket linked to the developer account (`pubsite_prod_<developerId>`). Before v0.9.93 these commands only printed guidance; they now do real network work, with their own error codes.257258| Code | Exit | Meaning | Fix |259|------|------|---------|-----|260| `REPORT_ACCESS_DENIED` | 4 | Credential is valid but not authorized to read the reports bucket | Play Console -> Users and permissions -> the service account -> Account permissions -> enable "View app information and download bulk reports (read-only)", wait a few minutes, then retry |261| `REPORT_AUTH_REJECTED` | 3 | Google rejected the token itself (HTTP 401) | Check the key with `gpc auth status`, verify the system clock, then `gpc auth clear-cache` and retry |262| `REPORT_BUCKET_UNKNOWN` | 2 | No bucket configured and no developer id to derive one from | Set `developerId` / `GPC_DEVELOPER_ID`, or pass `--bucket` / `GPC_REPORTS_BUCKET` / `reports.bucket` |263| `REPORT_BUCKET_INVALID` | 2 | The configured bucket name is not a valid GCS bucket name | Copy the exact Cloud Storage URI from Play Console -> Download reports (a `gs://` URI is accepted and reduced to the bucket name) |264| `REPORT_BUCKET_NOT_FOUND` | 4 | The bucket does not exist or is invisible to this account | Confirm the name; the default is `pubsite_prod_<developerId>` |265| `REPORT_OBJECT_NOT_FOUND` | 4 | No object matched the type / month / dimension | The error lists available dimensions or months; a month is only published after it ends |266| `REPORT_LIST_FAILED` | 4 | The bucket listing call failed | Retry; check network and `gpc doctor` |267| `REPORT_DOWNLOAD_FAILED` | 4 | The object fetch failed | Retry; check network |268| `REPORT_DECODE_FAILED` | 4 | The object could not be gunzipped or decoded from UTF-16 | Retry the download; if it persists, save the raw object with `--output-file` and report it |269| `REPORT_ARCHIVE_UNREADABLE` | 4 | A financial ZIP archive could not be read | Save it raw with `--output-file report.zip` and open it locally |270| `REPORT_MULTIPLE_ENTRIES` | 2 | A financial archive holds several CSVs, so there is nothing single to print | Use `--output-file report.zip` to save the archive, or `--json` to inline every entry |271| `INVALID_REPORT_DIMENSION` | 2 | `--dimension` is not one of the supported values | Use `overview`, `country`, `language`, `os_version`, `device`, `app_version`, `carrier`, or `traffic_source` (reviews reports have no dimension) |272| `MISSING_REQUIRED_OPTION` | 2 | A required flag such as `--month` or `--type` was omitted | Check the synopsis: stats downloads need `--month` and `--type` |273| `INVALID_LIMIT` | 2 | `--limit` is not a positive integer | Pass a positive whole number |274275`gpc doctor` includes a `reports-bucket` probe: it warns when the grant is missing (403/401) or the bucket name is wrong (404), so it is the fastest way to confirm setup before debugging a command.276277### 9. Debug mode278279Enable verbose output for any command:280281```bash282# Debug environment variable283GPC_DEBUG=1 gpc releases upload app.aab --track beta284285# JSON output for machine parsing286gpc releases upload app.aab --track beta --json287288# Combine for maximum detail289GPC_DEBUG=1 gpc releases upload app.aab --track beta --json 2>debug.log290```291292### 10. Retryable HTTP status codes293294GPC automatically retries the following HTTP status codes with exponential backoff:295296- **408** — Request Timeout297- **429** — Too Many Requests (rate limited)298- **5xx** — Server errors (500, 502, 503, etc.)299300Configure retry behavior:301```bash302export GPC_MAX_RETRIES=5 # Default: 5303export GPC_BASE_DELAY=1000 # Initial delay in ms304export GPC_MAX_DELAY=15000 # Max delay in ms305export GPC_UPLOAD_TIMEOUT=300000 # Upload timeout in ms (5 min)306```307308## Verification309310- `gpc doctor` passes all checks311- Failing command now succeeds or shows a clear, actionable error312- Exit code matches the expected category313- `--json` output includes `error.code`, `error.message`, and `error.suggestion`314315## Failure modes / debugging316317| Symptom | Likely Cause | Fix |318|---------|-------------|-----|319| `gpc doctor` fails on auth | Credentials not configured | Run `gpc setup` (v0.9.68+) or `gpc auth login` |320| `gpc doctor` fails on API | Service account lacks API access | Enable Google Play Developer API in GCP |321| `gpc doctor` quota warning | >80% of daily or per-minute API quota used | Reduce request frequency or request quota increase from Google (v0.9.71+) |322| `gpc doctor` plugin error | A configured plugin fails to load | Check plugin package version, reinstall, or remove from config (v0.9.71+) |323| `gpc doctor --verify` mismatch | Local keystore differs from Play signing cert | Register local key in Play Console or use Play App Signing (v0.9.75+) |324| All commands timeout | Network/proxy issue | Check `HTTPS_PROXY`, `GPC_CA_CERT`, `GPC_TIMEOUT` |325| Commands work locally, fail in CI | Missing env vars in CI | Set `GPC_SERVICE_ACCOUNT` and `GPC_APP` in CI secrets; run `gpc setup --auto` (v0.9.68+) |326| Env vars `GPC_SERVICE_ACCOUNT` / `GPC_APP` seem to be ignored | Active profile overriding env vars (pre-v0.9.81 bug) | Upgrade to v0.9.81+. Check active profile with `gpc config list`; env vars and flags now correctly override the profile. |327| `npm install -g @gpc-cli/cli` fails with `EUNSUPPORTEDPROTOCOL` | `workspace:*` specifiers leaked into published manifests (v0.9.77-v0.9.83) | Reinstall on v0.9.84+ or v0.9.85+: `npm install -g @gpc-cli/cli@latest`. Fixed in v0.9.84 (cli+core) and fully resolved in v0.9.85 (api package re-published). |328| `gpc doctor` warns on `reports-bucket` | Service account lacks the bulk-reports grant, or the bucket name is wrong | Enable "View app information and download bulk reports (read-only)" in Play Console, or set the exact bucket with `--bucket` / `GPC_REPORTS_BUCKET` (v0.9.93+) |329| Reports still denied right after granting the permission | Grant has not propagated, or a cached token predates it | Wait a few minutes, run `gpc auth clear-cache`, then retry (v0.9.93+) |330| JSON output has no `suggestion` | Unexpected error type | File a bug — all errors should have suggestions |331332## Related skills333334- **gpc-setup** — initial auth and config setup335- **gpc-ci-integration** — CI-specific troubleshooting336- **gpc-vitals-monitoring** — understanding threshold breaches337- **gpc-plugin-development** — debugging plugin issues