The CLI provides structured error handling with predictable exit codes following CI/CD best practices.
Exit Codes
Every command returns a numeric exit code that indicates the result:
asc apps list
echo $? # 0 = success
Exit Code Reference
Code Meaning Example 0Success Command completed successfully 1Generic error Unexpected failure, network error, or unknown issue 2Usage error Invalid flags, missing required arguments, or malformed command 3Authentication failure Missing credentials, invalid API key, or permission denied 4Resource not found App, build, or resource does not exist 5Conflict Resource already exists or version conflict
HTTP Status Mapping
The CLI maps HTTP status codes to exit codes:
4xx Client Errors
Formula: 10 + (status - 400)
HTTP Status Exit Code Description 400 Bad Request 10Invalid request parameters 401 Unauthorized 11Authentication required 403 Forbidden 12Permission denied 404 Not Found 4Resource not found (special case) 409 Conflict 5Resource conflict (special case) 422 Unprocessable 22Validation error
5xx Server Errors
Formula: 60 + (status - 500)
HTTP Status Exit Code Description 500 Internal Server Error 60API server error 502 Bad Gateway 62Gateway error 503 Service Unavailable 63Service temporarily unavailable
Exit codes follow a deterministic formula defined in cmd/exit_codes.go. This ensures consistent, scriptable error handling.
API Errors
The App Store Connect API returns structured error responses:
{
"errors" : [
{
"status" : "404" ,
"code" : "NOT_FOUND" ,
"title" : "The requested resource does not exist" ,
"detail" : "There is no app with ID '123456789'"
}
]
}
The CLI parses these errors and displays them in a human-readable format:
asc apps get --id 123456789
# Error: The requested resource does not exist: There is no app with ID '123456789'
# Exit code: 4
Well-Known Error Codes
The CLI recognizes standard App Store Connect error codes:
NOT_FOUND → Exit code 4
CONFLICT → Exit code 5
UNAUTHORIZED → Exit code 3
FORBIDDEN → Exit code 3
BAD_REQUEST → Exit code 10
These map to Go error sentinels:
// From internal/asc/errors.go
var (
ErrNotFound = errors . New ( "resource not found" )
ErrUnauthorized = errors . New ( "unauthorized" )
ErrForbidden = errors . New ( "forbidden" )
ErrBadRequest = errors . New ( "bad request" )
ErrConflict = errors . New ( "resource conflict" )
)
Associated Errors
Some API errors include additional details under meta.associatedErrors:
asc versions create --app APP_ID --version 1.0.0 --platform IOS
# Error: Version creation failed: The version string is invalid
#
# Associated errors for appStoreVersion:
# - Version string must follow semantic versioning (e.g., 1.0.0)
# - Version 1.0.0 already exists for this app
The CLI formats these errors with clear indentation and grouping.
Error Messages
All error messages go to stderr , not stdout:
# Success: data goes to stdout
asc apps list --output json > apps.json
# Failure: error goes to stderr, stdout is empty
asc apps get --id INVALID 2> error.log
# error.log contains: "Error: The requested resource does not exist: ..."
This allows safe piping and redirection:
# Pipe only successful output
asc apps list --output json | jq '.data[0].id'
# Capture errors separately
asc apps get --id APP_ID > output.json 2> errors.log
Handling Errors in Scripts
Exit Code Checks
#!/bin/bash
set -e # Exit on any error
asc apps list --output json > apps.json
if [ $? -eq 0 ]; then
echo "Success: $( jq '.data | length' apps.json) apps found"
fi
Specific Error Handling
#!/bin/bash
asc apps get --id " $APP_ID " --output json > app.json
EXIT_CODE = $?
case $EXIT_CODE in
0 )
echo "App found"
;;
4 )
echo "App not found, creating..."
asc apps create --name "My App" --bundle-id "com.example.app"
;;
3 )
echo "Authentication failed. Check ASC_KEY_ID and ASC_ISSUER_ID."
exit 1
;;
*)
echo "Unexpected error (exit code: $EXIT_CODE )"
exit 1
;;
esac
Retry on Transient Errors
#!/bin/bash
retry_count = 0
max_retries = 3
while [ $retry_count -lt $max_retries ]; do
asc apps list --output json > apps.json
exit_code = $?
# Success
if [ $exit_code -eq 0 ]; then
break
fi
# Retry on 5xx errors (exit codes 60-99)
if [ $exit_code -ge 60 ] && [ $exit_code -le 99 ]; then
retry_count = $(( retry_count + 1 ))
echo "Server error, retrying ( $retry_count / $max_retries )..." >&2
sleep 5
else
# Non-retryable error
echo "Fatal error (exit code: $exit_code )" >&2
exit $exit_code
fi
done
CI/CD Integration
GitHub Actions
- name : Fetch apps
id : fetch_apps
run : |
asc apps list --output json > apps.json
continue-on-error : true
- name : Handle errors
if : failure()
run : |
echo "Failed to fetch apps (exit code: $?)"
exit 1
GitLab CI
fetch_apps :
script :
- asc apps list --output json > apps.json
allow_failure :
exit_codes :
- 4 # Allow not found
Makefile
.PHONY : check-auth
check-auth :
@ asc auth status --output json > /dev/null 2>&1 || \
(echo "Error: Authentication failed. Run 'asc auth login'"; exit 1)
.PHONY : list-apps
list-apps : check-auth
asc apps list --output json > apps.json
Authentication Errors
Common authentication failures and solutions:
Missing Credentials
asc apps list
# Error: missing authentication. Run 'asc auth login' or 'asc auth init'
# Exit code: 1 (generic error, not 3)
Missing credentials return exit code 1, not 3. Exit code 3 is reserved for failed authentication (invalid credentials), not missing credentials.
Invalid API Key
asc apps list
# Error: unauthorized
# Exit code: 3
Solution: Verify your credentials:
Permission Denied
asc apps delete --id APP_ID --confirm
# Error: forbidden: You don't have permission to delete apps
# Exit code: 3
Solution: Check your App Store Connect role and permissions.
Debugging Errors
Enable debug logging with --debug or --api-debug:
# General debug output
asc apps list --debug
# HTTP request/response debug (redacts sensitive values)
asc apps list --api-debug
Debug output goes to stderr:
asc apps list --api-debug 2> debug.log
Environment Variables
# Enable API debug for all commands
export ASC_DEBUG = api
asc apps list
# Disable debug
unset ASC_DEBUG
Error Handling Best Practices
Always Check Exit Codes Use set -e in shell scripts or check $? after each command.
Separate stdout and stderr Redirect errors to a log file: asc apps list 2> errors.log.
Handle Expected Errors Exit code 4 (not found) is often expected. Handle it explicitly.
Retry Transient Errors Retry on exit codes 60-99 (5xx server errors) with exponential backoff.