Documentation Index
Fetch the complete documentation index at: https://docs.grantex.dev/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Grantex Python SDK uses a structured exception hierarchy. All exceptions inherit from GrantexError, so you can catch all SDK errors with a single handler or handle specific error types individually.
Exception Hierarchy
GrantexError (base)
├── GrantexApiError (non-2xx HTTP response)
│ └── GrantexAuthError (401 or 403)
├── GrantexTokenError (JWT verification / decoding failure)
└── GrantexNetworkError (timeout, connection error)
Import
from grantex import (
GrantexError,
GrantexApiError,
GrantexAuthError,
GrantexTokenError,
GrantexNetworkError,
)
GrantexError
The base exception for all Grantex SDK errors. Catch this to handle any SDK error:
from grantex import Grantex, GrantexError
with Grantex(api_key="gx_live_...") as client:
try:
agent = client.agents.get("agt_nonexistent")
except GrantexError as e:
print(f"Something went wrong: {e}")
GrantexApiError
Raised when the Grantex API returns a non-2xx HTTP response. Provides access to the HTTP status code, response body, and request ID.
from grantex import Grantex, GrantexApiError
with Grantex(api_key="gx_live_...") as client:
try:
agent = client.agents.get("agt_nonexistent")
except GrantexApiError as e:
print(f"Status code: {e.status_code}")
print(f"Message: {e}")
print(f"Response body: {e.body}")
print(f"Request ID: {e.request_id}")
Attributes
| Attribute | Type | Description |
|---|
status_code | int | The HTTP status code (e.g. 404, 422, 500). |
body | Any | The parsed response body (usually a dict) or raw text. |
request_id | str | None | The X-Request-Id header value (if present). |
The error message is extracted from the response body’s message or error field, falling back to "HTTP {status_code}".
GrantexAuthError
A subclass of GrantexApiError raised specifically for 401 (Unauthorized) and 403 (Forbidden) responses. Typically indicates an invalid or expired API key.
from grantex import Grantex, GrantexAuthError
with Grantex(api_key="gx_invalid_key") as client:
try:
agents = client.agents.list()
except GrantexAuthError as e:
print(f"Authentication failed ({e.status_code}): {e}")
# Handle: refresh API key, prompt user, etc.
GrantexAuthError has the same attributes as GrantexApiError.
GrantexTokenError
Raised when JWT verification fails. This occurs when using verify_grant_token() for offline verification or when grants.verify() receives an active: false response (revoked, expired, or unknown token) from the Grantex API.
from grantex import verify_grant_token, VerifyGrantTokenOptions, GrantexTokenError
try:
grant = verify_grant_token(
"invalid.jwt.token",
VerifyGrantTokenOptions(
jwks_uri="https://api.grantex.dev/.well-known/jwks.json",
),
)
except GrantexTokenError as e:
print(f"Token error: {e}")
Common causes:
- Token uses an algorithm other than RS256
- Token signature is invalid
- Token is expired
- Required claims are missing (
jti, sub, agt, dev, scp, iat, exp)
- Required scopes are not present
- JWKS endpoint is unreachable
- No matching RSA key found in the JWKS
GrantexNetworkError
Raised on network-level failures such as timeouts, DNS resolution errors, or connection refused. The original exception is available via the cause attribute.
from grantex import Grantex, GrantexNetworkError
with Grantex(api_key="gx_live_...", timeout=5.0) as client:
try:
agents = client.agents.list()
except GrantexNetworkError as e:
print(f"Network error: {e}")
print(f"Original exception: {e.cause}")
Attributes
| Attribute | Type | Description |
|---|
cause | BaseException | None | The underlying httpx exception that caused the failure. |
Best Practices
Catch Specific Errors First
Order your except clauses from most specific to least specific:
from grantex import (
Grantex,
GrantexAuthError,
GrantexApiError,
GrantexNetworkError,
GrantexError,
)
with Grantex(api_key="gx_live_...") as client:
try:
agent = client.agents.get("agt_abc123")
except GrantexAuthError as e:
# 401/403 -- invalid or expired API key
print(f"Auth failed: {e}")
except GrantexApiError as e:
# Other HTTP errors (404, 422, 500, etc.)
print(f"API error {e.status_code}: {e}")
except GrantexNetworkError as e:
# Timeout, connection refused, DNS failure
print(f"Network error: {e}")
except GrantexError as e:
# Catch-all for any other SDK error
print(f"Unexpected error: {e}")
Retry on Transient Errors
Network errors and certain HTTP status codes (429, 502, 503, 504) are often transient and safe to retry:
import time
from grantex import Grantex, GrantexApiError, GrantexNetworkError
def get_agent_with_retry(client, agent_id, max_retries=3):
for attempt in range(max_retries):
try:
return client.agents.get(agent_id)
except GrantexNetworkError:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # Exponential backoff
except GrantexApiError as e:
if e.status_code in (429, 502, 503, 504):
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
else:
raise # Non-retryable API error
Use Request ID for Support
When reporting issues, include the request_id from GrantexApiError:
from grantex import Grantex, GrantexApiError
with Grantex(api_key="gx_live_...") as client:
try:
client.agents.delete("agt_abc123")
except GrantexApiError as e:
print(f"Error: {e}")
if e.request_id:
print(f"Request ID for support: {e.request_id}")