Error Catalog
Every error is deterministic, categorized, and actionable. No mystery 500s.
Error Response Format
All errors return a consistent JSON envelope. Clients can parse the code field to programmatically handle any error condition.
Standard Error Response
{
"error": {
"code": "E1003",
"category": "CONTRACT",
"message": "Input validation failed: field 'email' does not match pattern",
"request_id": "req_abc123",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"field": "email",
"constraint": "pattern",
"expected": "^[\\w.-]+@[\\w.-]+$",
"received": "not-an-email"
}
}
}
| Field | Type | Description |
|---|---|---|
code | string | Unique error code (e.g., E1003). Stable across versions. |
category | string | Error category: CONTRACT, CAPABILITY, RUNTIME, DEPLOYMENT, AUTH |
message | string | Human-readable description of what went wrong |
request_id | string | Unique request identifier for correlation and support |
timestamp | string | ISO 8601 timestamp of when the error occurred |
details | object | Error-specific context (varies by error code) |
CONTRACT Errors (E1xxx)
Contract errors occur when a controller's contract definition is invalid, or when request/response data fails schema validation.
Contract Validation Failures
E1001 – E1005
5 errors
{
"error": {
"code": "E1001",
"category": "CONTRACT",
"message": "Invalid contract schema: 'capabilities' must be an array",
"request_id": "req_7f2a9b",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"path": "$.capabilities",
"expected_type": "array",
"received_type": "string",
"schema_version": "2.0"
}
}
}
- Validate your contract against the schema:
magic validate contract.json - Check the
details.pathfield to locate the exact issue in your contract - Refer to the Contracts documentation for the full specification
name, version, input, and output sections.
{
"error": {
"code": "E1002",
"category": "CONTRACT",
"message": "Missing required field: 'output' schema is required",
"request_id": "req_3e8c1d",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"missing_field": "output",
"contract_name": "ProcessOrder",
"required_fields": ["name", "version", "input", "output"]
}
}
}
- Check the
details.missing_fieldto identify which field is absent - Add the missing field to your contract JSON
- Run
magic validate contract.jsonto confirm all required fields are present
{
"error": {
"code": "E1003",
"category": "CONTRACT",
"message": "Input validation failed: field 'email' does not match pattern",
"request_id": "req_abc123",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"field": "email",
"constraint": "pattern",
"expected": "^[\\w.-]+@[\\w.-]+$",
"received": "not-an-email"
}
}
}
- Inspect
details.fieldanddetails.constraintto understand what failed - Fix the request payload to conform to the input schema
- Common issues: missing required fields, wrong types, pattern mismatches, values outside min/max range
{
"error": {
"code": "E1004",
"category": "CONTRACT",
"message": "Output validation failed: 'total' must be a number, got string",
"request_id": "req_d91f4a",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"field": "total",
"constraint": "type",
"expected": "number",
"received": "string",
"controller": "ProcessOrder",
"controller_version": "1.2.0"
}
}
}
- This is a controller bug -- the controller code returns data that violates its own contract
- Review the controller's return value and ensure it matches the output schema
- Test locally with
magic test ProcessOrder --validate-output
{
"error": {
"code": "E1005",
"category": "CONTRACT",
"message": "Contract version mismatch: requested v1.0, deployed v2.0",
"request_id": "req_82e6f0",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "ProcessOrder",
"requested_version": "1.0.0",
"deployed_version": "2.0.0",
"breaking_changes": true
}
}
}
- Update your client to target the deployed contract version
- If you need the old version, check if it is available via versioned routing:
/v1/controllers/ProcessOrder - Review the Releases page for migration guides between versions
CAPABILITY Errors (E2xxx)
Capability errors are raised when a controller attempts to access a resource it has not declared in its contract. Magic uses a default-deny model -- everything not explicitly permitted is blocked.
Capability Violations
E2001 – E2005
5 errors
{
"error": {
"code": "E2001",
"category": "CAPABILITY",
"message": "Capability not declared: 'db:write' is not in controller capabilities",
"request_id": "req_f14a2c",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"capability": "db:write",
"controller": "ReadOnlyReport",
"declared_capabilities": ["db:read"],
"action": "db.insert('orders', ...)"
}
}
}
- Add the missing capability to your contract's
capabilitiesarray - Include appropriate scoping (table allowlist, domain allowlist, etc.)
- Re-deploy the controller with
magic deploy
{
"error": {
"code": "E2002",
"category": "CAPABILITY",
"message": "Resource limit exceeded: query returned 15,000 rows (max: 10,000)",
"request_id": "req_c87d3e",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"resource": "db:read",
"limit_type": "max_rows",
"limit_value": 10000,
"actual_value": 15000,
"controller": "BulkExport"
}
}
}
- Add pagination to your query to stay within row limits
- If higher limits are needed, update the capability scope in your contract
- Contact your platform admin if limits are enforced at the organization level
{
"error": {
"code": "E2003",
"category": "CAPABILITY",
"message": "Network egress denied: 'evil.example.com' not in allowlist",
"request_id": "req_a4e2b1",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"destination": "evil.example.com",
"allowed_domains": ["api.stripe.com", "*.amazonaws.com"],
"controller": "PaymentProcessor"
}
}
}
- If the domain is legitimate, add it to the
http:egress.allowlist in your contract - Wildcard patterns are supported (e.g.,
*.stripe.com) - If this was unexpected, investigate your controller for unintended network calls
{
"error": {
"code": "E2004",
"category": "CAPABILITY",
"message": "Database table not in allowlist: 'users_private' is not accessible",
"request_id": "req_91bc4f",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"table": "users_private",
"allowed_tables": ["orders", "products", "order_items"],
"operation": "SELECT",
"controller": "OrderLookup"
}
}
}
- Add the table to your contract's
db:read.tablesordb:write.tablesallowlist - Consider principle of least privilege -- does this controller really need access to this table?
- Re-deploy after updating the contract
secrets:read capability scope. Secrets are strictly scoped per-controller with no cross-controller access.
{
"error": {
"code": "E2005",
"category": "CAPABILITY",
"message": "Secret key not authorized: 'DATABASE_URL' is not in allowed secrets",
"request_id": "req_e63a8b",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"secret_key": "DATABASE_URL",
"allowed_keys": ["STRIPE_SECRET_KEY", "WEBHOOK_SIGNING_KEY"],
"controller": "PaymentProcessor"
}
}
}
- Add the secret key to your contract's
secrets:read.keysallowlist - Ensure the secret exists in the runtime's secret store
- Review access: controllers should only access secrets they genuinely need
RUNTIME Errors (E3xxx)
Runtime errors occur during controller execution when resource limits are hit or the sandbox environment fails to initialize properly.
Execution Failures
E3001 – E3005
5 errors
{
"error": {
"code": "E3001",
"category": "RUNTIME",
"message": "Controller timeout exceeded: execution killed after 30s",
"request_id": "req_4b7c9a",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "DataAggregator",
"timeout_seconds": 30,
"elapsed_seconds": 30.002,
"signal": "SIGKILL"
}
}
}
- Optimize controller logic -- reduce database queries, add caching, avoid unnecessary computation
- Increase the timeout in your contract's
resources.timeoutfield (max 300s) - Consider breaking long-running work into smaller async steps
{
"error": {
"code": "E3002",
"category": "RUNTIME",
"message": "Memory limit exceeded: process killed (OOM) at 256Mi",
"request_id": "req_d3f1e8",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "ImageProcessor",
"memory_limit": "256Mi",
"peak_usage": "256Mi",
"enforcement": "cgroup_oom_kill"
}
}
}
- Profile your controller's memory usage locally
- Reduce in-memory data (stream instead of buffering, use pagination)
- Increase the memory limit in your contract's
resources.memoryfield (max 2Gi)
{
"error": {
"code": "E3003",
"category": "RUNTIME",
"message": "CPU limit exceeded: throttled at 0.5 cores for 10s",
"request_id": "req_7a2e9c",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "CryptoHasher",
"cpu_limit": "0.5 cores",
"throttle_duration_ms": 10000,
"enforcement": "cgroup_cpu_max"
}
}
}
- Optimize CPU-intensive operations (algorithmic improvements, avoiding busy loops)
- Increase the CPU limit in your contract's
resources.cpufield (max 2.0 cores) - Offload heavy computation to external services via
http:egress
{
"error": {
"code": "E3004",
"category": "RUNTIME",
"message": "Sandbox initialization failed: unable to create cgroup",
"request_id": "req_b5c8d2",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"stage": "cgroup_creation",
"reason": "cgroup hierarchy not available",
"host": "worker-03"
}
}
}
- This is an infrastructure issue -- check that the host supports cgroups v2
- Verify the runtime has sufficient permissions to create process namespaces
- Retry the request; if persistent, check
magic healthfor system status
{
"error": {
"code": "E3005",
"category": "RUNTIME",
"message": "Controller not found: 'SendInvoice' is not deployed",
"request_id": "req_1f9a7e",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "SendInvoice",
"available_controllers": ["ProcessOrder", "LookupCustomer", "GenerateReport"]
}
}
}
- Verify the controller name is spelled correctly (names are case-sensitive)
- Check deployed controllers with
magic list - If the controller was recently deployed, it may still be initializing -- wait a few seconds and retry
DEPLOYMENT Errors (E4xxx)
Deployment errors occur during controller lifecycle operations: deploy, hot-reload, rollback, and registry management.
Deploy & Lifecycle Failures
E4001 – E4005
5 errors
{
"error": {
"code": "E4001",
"category": "DEPLOYMENT",
"message": "Deployment validation failed: controller entrypoint not found",
"request_id": "req_8c4f2a",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "NewFeature",
"validation_errors": [
"entrypoint 'handler.py' not found in package",
"dependency 'numpy' not in approved list"
]
}
}
}
- Review all validation errors in
details.validation_errors - Ensure the entrypoint file exists and matches the contract declaration
- Run
magic validate --pre-deploy ./controller/locally before deploying
--force flag to replace.
{
"error": {
"code": "E4002",
"category": "DEPLOYMENT",
"message": "Controller already exists: 'ProcessOrder@2.0.0' is deployed",
"request_id": "req_5d3b7c",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "ProcessOrder",
"version": "2.0.0",
"deployed_at": "2026-02-10T14:30:00Z",
"deployed_by": "admin@company.com"
}
}
}
- Increment the version number in your contract if this is a new release
- Use
magic deploy --forceto replace the existing version (caution: no automatic rollback) - Use
magic deploy --hot-reloadfor zero-downtime updates to the same version
{
"error": {
"code": "E4003",
"category": "DEPLOYMENT",
"message": "Hot-reload failed: health check did not pass within 15s",
"request_id": "req_2e8f4d",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "ProcessOrder",
"previous_version": "1.9.0",
"target_version": "2.0.0",
"reason": "health_check_timeout",
"rollback_status": "automatic_rollback_complete"
}
}
}
- The previous version is still running -- no downtime occurred
- Check your controller's initialization logic for errors or slow startup
- Review logs with
magic logs ProcessOrder --since 5mfor details
{
"error": {
"code": "E4004",
"category": "DEPLOYMENT",
"message": "Rollback target not found: version '1.0.0' not in history",
"request_id": "req_6a1c3e",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"controller": "ProcessOrder",
"requested_version": "1.0.0",
"available_versions": ["2.0.0", "1.9.0", "1.8.0", "1.7.0", "1.6.0"],
"retention_policy": 5
}
}
}
- Check available rollback targets in
details.available_versions - Use
magic history ProcessOrderto see the full deployment timeline - If the version was purged, re-deploy from source
{
"error": {
"code": "E4005",
"category": "DEPLOYMENT",
"message": "Registry full: 100/100 controller slots used",
"request_id": "req_9b5d1f",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"current_count": 100,
"max_count": 100,
"plan": "standard",
"upgrade_url": "https://magic.threadsync.io/enterprise.html"
}
}
}
- Remove unused controllers with
magic undeploy ControllerName - Review deployed controllers with
magic list --sort-by=last-invokedto find stale entries - Upgrade to Enterprise for higher registry limits
AUTH Errors (E5xxx)
Authentication and authorization errors occur when API credentials are invalid, expired, or lack sufficient permissions for the requested operation.
Authentication & Authorization
E5001 – E5005
5 errors
{
"error": {
"code": "E5001",
"category": "AUTH",
"message": "Invalid API key: the provided key is not recognized",
"request_id": "req_c2a4e6",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"key_prefix": "mk_live_7f2a...",
"auth_method": "api_key",
"header": "X-API-Key"
}
}
}
- Verify the API key is correct and has not been rotated
- Ensure you are using the correct header:
X-API-Key - Generate a new key from the admin dashboard if the current key was revoked
{
"error": {
"code": "E5002",
"category": "AUTH",
"message": "Token expired: JWT expired 15 minutes ago",
"request_id": "req_a8d3f1",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"expired_at": "2026-02-12T17:45:00Z",
"token_type": "bearer",
"issuer": "magic.threadsync.io"
}
}
}
- Refresh the token using your refresh token endpoint
- Implement automatic token refresh in your client before expiry
- If using SSO, re-authenticate through your identity provider
{
"error": {
"code": "E5003",
"category": "AUTH",
"message": "Insufficient permissions: 'deploy' requires 'admin' role",
"request_id": "req_f7b2c4",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"action": "deploy",
"required_role": "admin",
"current_role": "viewer",
"user": "dev@company.com"
}
}
}
- Request the required role from your organization admin
- Check your current permissions with
magic whoami - Use a service account with appropriate permissions for CI/CD pipelines
Retry-After header indicating when to retry.
{
"error": {
"code": "E5004",
"category": "AUTH",
"message": "Rate limit exceeded: 1000 requests/minute limit reached",
"request_id": "req_3e9a1b",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"limit": 1000,
"window": "1m",
"current": 1001,
"retry_after_seconds": 42,
"plan": "standard"
}
}
}
- Respect the
Retry-Afterheader and implement exponential backoff - Add client-side rate limiting to stay within your quota
- Upgrade to Enterprise for higher rate limits
{
"error": {
"code": "E5005",
"category": "AUTH",
"message": "IP not allowlisted: '203.0.113.42' is not in approved ranges",
"request_id": "req_8d2f6a",
"timestamp": "2026-02-12T18:00:00Z",
"details": {
"source_ip": "203.0.113.42",
"allowed_ranges": ["10.0.0.0/8", "192.168.1.0/24", "198.51.100.0/24"],
"policy": "organization"
}
}
}
- Add the source IP or CIDR range to your organization's IP allowlist
- If connecting from a VPN or proxy, ensure the egress IP is allowlisted
- Contact your organization admin to update the IP policy