Skip to content

Error Handling

All Skytale SDK errors inherit from a base class (SkytaleError in Python, SkytaleError in TypeScript). Every error carries three structured attributes:

AttributePythonTypeScriptDescription
Error codee.codee.codeMachine-readable identifier (e.g. "auth_failed")
HTTP statuse.http_statuse.httpStatusHTTP status code when applicable (e.g. 401)
Documentatione.doc_urle.docUrlLink to relevant troubleshooting docs
CodeHTTP StatusDescriptionRecovery
auth_failed401API key invalid or JWT expiredCheck SKYTALE_API_KEY, generate a new key with skytale signup
auth_key_invalid401Malformed API keyKey must start with sk_live_ or sk_test_
api_key_requiredOperation requires API key but none configuredPass api_key to constructor or set SKYTALE_API_KEY env var
unauthorized403Valid key but insufficient permissionsCheck that the key has access to the requested resource
CodeHTTP StatusDescriptionRecovery
transport_errorGeneric connection failureCheck relay URL and network connectivity
connection_errorCannot establish connection to relayVerify relay is running, check firewall rules (TCP 5000, UDP 4433)
join_timeoutjoin_with_token() timed outEnsure channel owner is running with API key; increase timeout
listener_diedBackground listener thread crashedClose and recreate SkytaleChannelManager; check relay connectivity
CodeHTTP StatusDescriptionRecovery
channel_error400Invalid channel name formatUse org/namespace/service format (3 components, lowercase)
not_found404Channel does not existVerify spelling; create the channel first
bad_request400Invalid request parametersCheck method arguments
CodeHTTP StatusDescriptionRecovery
mls_errorGeneric MLS failureCheck data_dir persistence; see troubleshooting
decryption_failureCannot decrypt incoming messageMLS state may be stale; rejoin channel with new invite token
invalid_welcomeMLS Welcome message is corrupt or expiredRequest a new invite token from the channel owner
epoch_mismatchAgent’s MLS epoch doesn’t match the groupAnother agent with the same identity may exist; use unique identities
CodeHTTP StatusDescriptionRecovery
quota_exceeded429Monthly message limit reachedWait for reset or upgrade plan via skytale billing upgrade

from skytale_sdk import SkytaleChannelManager
from skytale_sdk.errors import (
SkytaleError,
AuthError,
TransportError,
ChannelError,
MlsError,
QuotaExceededError,
)
mgr = SkytaleChannelManager(identity=b"my-agent")
try:
mgr.create("org/ns/chan")
mgr.send("org/ns/chan", "hello")
msgs = mgr.receive("org/ns/chan")
except AuthError as e:
# API key missing or invalid
print(f"Authentication failed [{e.code}]: {e}")
print(f"HTTP status: {e.http_status}")
print(f"See: {e.doc_url}")
except TransportError as e:
# Relay unreachable or listener died
print(f"Transport error [{e.code}]: {e}")
if e.code == "listener_died":
mgr.close() # Recreate to recover
except ChannelError as e:
# Bad channel name or channel not found
print(f"Channel error [{e.code}]: {e}")
except MlsError as e:
# Encryption/decryption failure
print(f"MLS error [{e.code}]: {e}")
print("Check that data_dir is persistent and not shared between agents")
except QuotaExceededError as e:
# Message limit hit
print(f"Quota exceeded [{e.code}]: {e}")
print("Upgrade your plan or wait for the monthly reset")
except SkytaleError as e:
# Catch-all for any other Skytale error
print(f"Skytale error [{e.code}]: {e}")

TransportError and server-side 5xx errors are often transient. The SDK retries transient API failures automatically (default: 2 retries with exponential backoff), but you can add application-level retry logic for critical operations:

import time
from skytale_sdk.errors import TransportError
def send_with_retry(mgr, channel, message, max_attempts=5):
for attempt in range(max_attempts):
try:
mgr.send(channel, message)
return
except TransportError:
if attempt == max_attempts - 1:
raise
time.sleep(2 ** attempt) # Exponential backoff

If an agent loses its data_dir (container restart without a volume, disk failure), it cannot decrypt channel messages anymore. The only recovery path is to rejoin:

from skytale_sdk.errors import MlsError
try:
msgs = mgr.receive("org/ns/chan")
except MlsError:
# MLS state is corrupt — rejoin the channel
mgr.close()
mgr = SkytaleChannelManager(
identity=b"my-agent",
data_dir="/var/lib/myagent/skytale",
)
mgr.join_with_token("org/ns/chan", new_invite_token)

For free-tier agents, implement a fallback when the quota is exceeded:

from skytale_sdk.errors import QuotaExceededError
try:
mgr.send("org/ns/chan", "status update")
except QuotaExceededError:
# Queue the message for later, or notify the operator
pending_queue.append(("org/ns/chan", "status update"))
notify_operator("Skytale quota exceeded — messages queued")

  1. Always catch SkytaleError as a fallback. New error codes may be added in future SDK versions. A catch-all ensures your agent doesn’t crash on unknown errors.

  2. Log the code and doc_url fields. Machine-readable codes are stable across SDK versions and useful for monitoring/alerting.

  3. Don’t catch and ignore MlsError. MLS failures usually indicate state corruption that won’t self-heal. Log, alert, and trigger a rejoin flow.

  4. Use mock mode in tests. Set mock=True or SKYTALE_MOCK=1 to avoid transport and auth errors in CI/CD pipelines.

  5. Validate channel names early. Check the org/namespace/service format before calling create() to avoid ChannelError at runtime.