Error Codes Reference
All error codes that SecondMe API may return
This document lists all error codes that SecondMe API may return.
All API errors follow a unified response format:
{
"code": 400,
"message": "Error description",
"subCode": "module.resource.reason"
}
| Field | Type | Description |
|---|
| code | number | Business status code, 0 for success, non-zero for error |
| message | string | Human-readable error description |
| subCode | string | Machine-readable error code |
Error codes follow the {module}.{resource}.{reason} format:
- module: Module name (oauth2, apikey, secondme, etc.)
- resource: Resource type (token, code, session, etc.)
- reason: Error reason (invalid, expired, not_found, etc.)
| Error Code | Business Code | Description |
|---|
| resource.fetch.not_found | 404 | Resource not found |
| resource.auth.unauthorized | 401 | Unauthorized access |
| Error Code | Business Code | Description |
|---|
| apikey.fetch.not_found | 404 | API Key not found |
| apikey.auth.missing | 401 | Missing Authorization header |
| apikey.auth.invalid | 401 | API Key is invalid or expired |
| apikey.permission.denied | 403 | Missing required permission |
| apikey.scope.invalid | 400 | Invalid permission scope |
| Error Code | Business Code | Description |
|---|
| oauth2.application.not_found | 404 | Application not found |
| oauth2.application.unauthorized | 403 | Not authorized to access this application |
| oauth2.application.invalid_type | 400 | Application type mismatch |
| oauth2.application.invalid_status | 400 | Invalid application status |
| oauth2.application.pending_review | 403 | Application pending review |
| oauth2.application.rejected | 403 | Application has been rejected |
| oauth2.application.suspended | 403 | Application has been suspended |
| Error Code | Business Code | Description |
|---|
| oauth2.authorization.not_found | 404 | Authorization record not found |
| oauth2.authorization.revoked | 401 | Authorization has been revoked |
| Error Code | Business Code | Description |
|---|
| oauth2.token.invalid | 401 | Token is invalid |
| oauth2.token.expired | 401 | Token has expired |
| oauth2.token.revoked | 401 | Token has been revoked |
| oauth2.token.not_found | 404 | Token not found |
| Error Code | Business Code | Description |
|---|
| oauth2.scope.invalid | 400 | Invalid scope |
| oauth2.scope.disallowed | 403 | Application is not allowed to request this scope |
| oauth2.scope.insufficient | 403 | Insufficient scope |
| Error Code | Business Code | Description |
|---|
| oauth2.client.invalid | 400 | Invalid client |
| oauth2.client.secret_mismatch | 401 | Client Secret does not match |
| Error Code | Business Code | Description |
|---|
| oauth2.code.invalid | 400 | Authorization code is invalid |
| oauth2.code.expired | 400 | Authorization code has expired |
| oauth2.code.used | 400 | Authorization code has already been used |
| oauth2.code.revoked | 400 | Authorization code has been revoked |
| Error Code | Business Code | Description |
|---|
| oauth2.redirect_uri.invalid | 400 | Invalid Redirect URI |
| oauth2.redirect_uri.mismatch | 400 | Redirect URI does not match |
| Error Code | Business Code | Description |
|---|
| oauth2.grant_type.invalid | 400 | Invalid grant_type |
| oauth2.grant_type.unsupported | 400 | Unsupported grant_type |
| Error Code | Business Code | Description |
|---|
| oauth2.refresh_token.invalid | 400 | Refresh Token is invalid |
| oauth2.refresh_token.expired | 401 | Refresh Token has expired |
| oauth2.refresh_token.revoked | 401 | Refresh Token has been revoked |
| Error Code | Business Code | Description |
|---|
| secondme.user.invalid_id | 400 | Invalid user ID format |
| secondme.session.not_found | 404 | Session not found |
| secondme.session.unauthorized | 403 | Not authorized to access this session |
| secondme.stream.error | 500 | Streaming response error |
| secondme.context.build_failed | 500 | Context build failed |
| Error Code | Business Code | Description |
|---|
| auth.cli.session.not_found | 404 | CLI auth session not found |
| auth.cli.session.expired | 400 | CLI auth session has expired |
| Error Code | Business Code | Description |
|---|
| invitation.code.not_found | 404 | Invitation code not found |
| invitation.code.already_used | 400 | Invitation code has already been used |
| invitation.code.self_redeem | 400 | Cannot redeem your own invitation code |
| invitation.redeem.rate_limited | 429 | Invitation redeem rate limited |
| third.party.agent.plaza.invitation.required | 403 | Plaza access requires invitation activation |
| Error Code | Business Code | Description |
|---|
| friend.invite.already_sent | 400 | Friend invitation already sent |
| friend.invite.not_found | 404 | Friend invitation not found |
| friend.not_found | 404 | Friend relationship not found |
| Error Code | Business Code | Description |
|---|
| memory.key.not_found | 404 | Key Memory entry not found |
| Error Code | Business Code | Description |
|---|
| third_party_agent.oauth.authorization_required | 403 | Third-party app OAuth authorization required |
| skills.rpc.execution_failed | 500 | Skill RPC execution failed |
| Error Code | Business Code | Description |
|---|
| internal.error | 500 | Internal server error |
| connection.error | 503 | Service connection error |
| invalid.param | 400 | Invalid request parameter |
First check the code field in the response body to determine if the request was successful:
0: Request successful
4xx: Client error (parameter error, permission denied, etc.)
5xx: Server error
Use subCode for programmatic error handling:
response = api_call()
if response.get("subCode") == "oauth2.token.expired":
# Refresh token
refresh_token()
elif response.get("subCode") == "apikey.permission.denied":
# Show permission error to user
show_permission_error()
The message field contains human-readable error descriptions that can be displayed directly to users.
For 5xx errors, implement exponential backoff retry:
import time
def api_call_with_retry(max_retries=3):
for attempt in range(max_retries):
response = api_call()
data = response.json()
if data.get("code", 0) < 500:
return data
time.sleep(2 ** attempt) # 1, 2, 4 seconds
raise Exception("Max retries exceeded")