Error Reference
Every KruxOS error is a StructuredError containing a machine-readable code, a human description, an agent-facing description, recovery suggestions, and a retryable flag. This page documents every error type your agent or SDK may encounter.
How to read this catalogue
Each entry lists:
| Field |
Meaning |
| Error type |
The error_type string returned in the StructuredError JSON |
| Retryable |
Whether the SDK will auto-retry or you should retry manually |
| Retry after |
Suggested wait time before retrying (if applicable) |
| Recovery actions |
Machine-readable action names returned in recovery_actions |
StructuredError JSON shape
{
"error_type": "PolicyDenied",
"description": "Policy rule 'deny-network' denied execution of 'network.http'",
"agent_description": "Your request to execute 'network.http' was blocked by policy rule 'deny-network'...",
"recovery_actions": [
{
"action": "check_policy",
"description": "Review your agent's policy group and permissions.",
"capability": "agent.policy",
"inputs": null
}
],
"retryable": false,
"retry_after": null,
"context": {
"rule": "deny-network",
"capability": "network.http"
}
}
Python SDK exception mapping
Every error_type maps to a Python exception class in kruxos.errors. All exceptions inherit from KruxOSError and expose .structured, .retryable, and .error_type properties.
from kruxos.errors import PolicyDeniedError, RateLimitedError
try:
result = await os.call_async("filesystem.write", path="/etc/passwd", content="x")
except PolicyDeniedError as e:
print(e.structured.recovery_actions) # [RecoveryAction(...)]
print(e.retryable) # False
except RateLimitedError as e:
print(e.retry_after) # 30.0
Authentication errors
These errors occur during the WebSocket handshake before a session is established.
auth.invalid_credentials
|
|
| Message |
Invalid agent name or API key. |
| Cause |
The agent name does not exist, or the API key does not match. |
| Fix |
Verify the agent name with kruxos agent list. Re-check the API key for copy-paste errors (trailing whitespace, truncation). If the key was rotated, use the new key. |
| Retryable |
No |
| SDK exception |
AuthenticationError |
| Recovery actions |
check_credentials |
auth.agent_revoked
|
|
| Message |
Agent 'my-agent' has been revoked. |
| Cause |
An administrator revoked the agent via kruxos agent revoke. |
| Fix |
Contact the administrator to reinstate the agent, or create a new one with kruxos agent create. |
| Retryable |
No |
| SDK exception |
AuthenticationError |
| Recovery actions |
contact_admin, create_new_agent |
auth.rate_limited
|
|
| Message |
Too many authentication attempts. Max N per minute. |
| Cause |
Too many failed authentication attempts from the same IP address. |
| Fix |
Wait 60 seconds before retrying. If you are scripting connections, add a delay between retries. |
| Retryable |
Yes |
| SDK exception |
RateLimitedError |
| Recovery actions |
wait_and_retry |
Session errors
NotAuthenticated
|
|
| Message |
Not authenticated: |
| Cause |
The request could not be authenticated. This can happen if credentials are missing from the connection handshake. |
| Fix |
Reconnect with valid credentials (agent name + API key). |
| Retryable |
No |
| SDK exception |
AuthenticationError |
| Recovery actions |
reconnect |
SessionExpired
|
|
| Message |
Session '{session_id}' has expired |
| Cause |
The session timed out due to inactivity, or the Gateway restarted and the session was not recovered from the checkpoint. |
| Fix |
Reconnect to establish a new session. The SDK reconnects automatically with exponential backoff. |
| Retryable |
No |
| SDK exception |
SessionExpiredError |
| Recovery actions |
reconnect |
| Context |
session_id |
Policy errors
PolicyDenied
|
|
| Message |
Policy rule '{rule}' denied execution of '{capability}' |
| Cause |
The policy engine blocked this capability invocation. The agent's permission tier does not allow the requested operation. |
| Fix |
Check which policy rule is blocking with kruxos config check-policy --agent <name> --capability <cap>. Edit the policy YAML to adjust the tier, or ask a supervisor to grant permission. |
| Retryable |
No |
| SDK exception |
PolicyDeniedError |
| Recovery actions |
check_policy (calls agent.policy), request_escalation |
| Context |
rule, capability |
ApprovalPending
|
|
| Message |
Approval pending for '{capability}' (request: {request_id}) |
| Cause |
The capability's policy tier requires human approval before execution. The request is queued and waiting for a supervisor. |
| Fix |
Wait for a supervisor to approve via kruxos approve accept <request_id> or the dashboard. Poll for the decision using the request ID. |
| Retryable |
No |
| SDK exception |
ApprovalRequiredError (has .request_id property) |
| Recovery actions |
wait_for_approval, check_status |
| Context |
request_id, capability |
ApprovalRejected
|
|
| Message |
Approval rejected for request {request_id}: {reason} |
| Cause |
A supervisor reviewed and rejected the capability request. |
| Fix |
Read the rejection reason. Modify the operation parameters (e.g., use a less sensitive path, reduce scope) and submit a new request. Contact the supervisor for guidance. |
| Retryable |
No |
| SDK exception |
ApprovalRejectedError |
| Recovery actions |
modify_and_retry, contact_supervisor |
| Context |
request_id, reason |
|
|
| Message |
Invalid input: field '{field}' -- |
| Cause |
A capability input parameter failed validation (wrong type, missing required field, out of range). |
| Fix |
Read the reason and correct the field value. To inspect a capability's schema, call MCP tools/list (or JSON-RPC capabilities.list) and find the entry by name — v0.0.1 does not ship a kruxos cap CLI subcommand. |
| Retryable |
No |
| SDK exception |
InvalidInputError |
| Recovery actions |
fix_input |
| Context |
field, reason |
PathOutOfScope
|
|
| Message |
Path '{path}' is outside the agent's allowed scope |
| Cause |
The file path is outside the agent's workspace directory. Agents are sandboxed to their assigned workspace. |
| Fix |
Use a path within the workspace (typically /data/kruxos/workspace/<agent>/). Check workspace boundaries with the agent.session capability. |
| Retryable |
No |
| SDK exception |
PathOutOfScopeError |
| Recovery actions |
check_scope (calls agent.session), use_workspace_path |
| Context |
path |
FileNotFound
|
|
| Message |
File not found: |
| Cause |
The specified file does not exist at the given path. |
| Fix |
Verify the path spelling and case sensitivity. List the parent directory to find the correct filename. |
| Retryable |
No |
| SDK exception |
FileNotFoundError |
| Recovery actions |
list_directory (calls filesystem.list on parent dir), check_path |
| Context |
path |
PermissionDenied
|
|
| Message |
Permission denied: cannot {operation} '{path}' |
| Cause |
The OS denied the operation on the file. The file exists, but the sandbox does not grant the required access. |
| Fix |
Check file permissions with filesystem.stat. If the file is owned by root or another user, ask a supervisor to adjust sandbox permissions. |
| Retryable |
No |
| SDK exception |
PermissionDeniedError |
| Recovery actions |
check_permissions (calls filesystem.stat), request_access |
| Context |
path, operation |
Resource and rate limit errors
ResourceExhausted
|
|
| Message |
Resource exhausted: {resource} at {current} (limit: {limit}) |
| Cause |
A quota or system resource limit was reached (disk space, state quota, memory, open files). |
| Fix |
Check current usage with system.resources. Clean up unused data (delete old state keys, remove temporary files). To increase quotas, edit /etc/kruxos/gateway.yaml. |
| Retryable |
No |
| SDK exception |
ResourceExhaustedError |
| Recovery actions |
check_usage (calls system.resources), cleanup |
| Context |
resource, limit, current |
RateLimited
|
|
| Message |
Rate limited: {limit} requests per {window_seconds}s exceeded |
| Cause |
The agent exceeded its capability invocation rate limit. |
| Fix |
Wait the specified retry_after seconds, then retry. To adjust rate limits, modify the policy YAML. |
| Retryable |
Yes |
| Retry after |
retry_after_seconds (from context) |
| SDK exception |
RateLimitedError (has .retry_after property) |
| Recovery actions |
wait_and_retry |
| Context |
limit, window_seconds, retry_after_seconds |
Timeout
|
|
| Message |
Operation '{operation}' timed out after {timeout_seconds}s |
| Cause |
The capability did not complete within the allowed time. The operation may still be running in the background. |
| Fix |
Retry the operation. If it consistently times out, try with a longer timeout value or break the work into smaller operations. |
| Retryable |
Yes |
| SDK exception |
TimeoutError |
| Recovery actions |
retry, increase_timeout |
| Context |
operation, timeout_seconds |
Concurrency and service errors
ConflictError
|
|
| Message |
Conflict: {resource} was modified concurrently |
| Cause |
Another agent or operation modified the resource since it was last read (optimistic locking failure). |
| Fix |
Re-read the current version of the resource, then retry the update with the new version number. |
| Retryable |
Yes |
| SDK exception |
ConflictError |
| Recovery actions |
re_read |
| Context |
resource, expected_version, actual_version |
ServiceUnavailable
|
|
| Message |
Service '{service}' is unavailable: |
| Cause |
An external service (Gmail, Slack, etc.) or internal subsystem is temporarily unavailable. |
| Fix |
Wait and retry. The service proxy automatically retries queued operations. Check service status with system.health. |
| Retryable |
Yes |
| Retry after |
60 seconds |
| SDK exception |
ServiceUnavailableError |
| Recovery actions |
retry_later, check_service_status (calls system.health) |
| Context |
service, reason |
Service Proxy errors
These errors are specific to the Service Proxy framework and external service integrations.
proxy.service_error
|
|
| Message |
External service {service} returned an error: {message} |
| Cause |
The external service (e.g., Gmail API) returned an error response. |
| Fix |
Wait 60 seconds and retry. If the error persists, check the service status and your OAuth token validity. |
| Retryable |
Yes |
| Retry after |
60 seconds |
| Recovery actions |
retry_later |
proxy.batch_protection
|
|
| Message |
Batch protection triggered: {count} {operation} writes exceeds threshold ({threshold}) |
| Cause |
The agent attempted more write operations than the safety threshold allows. This is a safeguard against accidentally sending hundreds of emails or making bulk destructive changes. |
| Fix |
Request supervisor approval for the batch operation. Reduce the batch size, or ask an admin to adjust the threshold. |
| Retryable |
No |
| Recovery actions |
request_approval |
| Context |
operation, count, threshold |
Error type quick reference
| Error type |
Retryable |
SDK exception |
Category |
auth.invalid_credentials |
No |
AuthenticationError |
Auth |
auth.agent_revoked |
No |
AuthenticationError |
Auth |
auth.rate_limited |
Yes |
RateLimitedError |
Auth |
NotAuthenticated |
No |
AuthenticationError |
Session |
SessionExpired |
No |
SessionExpiredError |
Session |
PolicyDenied |
No |
PolicyDeniedError |
Policy |
ApprovalPending |
No |
ApprovalRequiredError |
Policy |
ApprovalRejected |
No |
ApprovalRejectedError |
Policy |
InvalidInput |
No |
InvalidInputError |
Input |
PathOutOfScope |
No |
PathOutOfScopeError |
Input |
FileNotFound |
No |
FileNotFoundError |
Input |
PermissionDenied |
No |
PermissionDeniedError |
Input |
ResourceExhausted |
No |
ResourceExhaustedError |
Resource |
RateLimited |
Yes |
RateLimitedError |
Resource |
Timeout |
Yes |
TimeoutError |
Resource |
ConflictError |
Yes |
ConflictError |
Concurrency |
ServiceUnavailable |
Yes |
ServiceUnavailableError |
Service |
proxy.service_error |
Yes |
ServiceUnavailableError |
Proxy |
proxy.batch_protection |
No |
CapabilityError |
Proxy |
Handling errors in the SDK
Catch specific errors
from kruxos.errors import (
PolicyDeniedError,
ApprovalRequiredError,
RateLimitedError,
TimeoutError,
ConflictError,
)
try:
result = await os.call_async("filesystem.write", path="output.txt", content=data)
except PolicyDeniedError as e:
# Not allowed -- check policy
print(f"Blocked by rule: {e.structured.context['rule']}")
except ApprovalRequiredError as e:
# Wait for human approval
print(f"Waiting for approval: {e.request_id}")
except RateLimitedError as e:
# Back off and retry
await asyncio.sleep(e.retry_after)
except TimeoutError:
# Retry with longer timeout
pass
except ConflictError:
# Re-read and retry
pass
Check retryability generically
from kruxos.errors import KruxOSError
try:
result = await os.call_async("process.run", command=["make", "build"])
except KruxOSError as e:
if e.retryable:
# Safe to retry after a delay
await asyncio.sleep(e.structured.retry_after or 5)
else:
# Inspect recovery_actions for next steps
for action in e.structured.recovery_actions:
print(f" Try: {action.description}")
Use recovery actions programmatically
Recovery actions may include a capability field suggesting which capability to call:
except FileNotFoundError as e:
for action in e.structured.recovery_actions:
if action.capability:
# Call the suggested capability
result = await os.call_async(action.capability, **(action.inputs or {}))