Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Errors

ScaiVault error responses are structured and stable. Your code branches on error.code, not on HTTP status alone or string-matching the message.

Error envelope#

Every error response:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "error": {
    "code": "secret_not_found",
    "message": "Secret 'environments/production/missing' not found",
    "details": {
      "path": "environments/production/missing"
    },
    "request_id": "req_abc123"
  }
}
  • code — machine-readable code from a stable vocabulary. Branch on this.
  • message — human-readable description. Display or log as-is.
  • details — optional, code-specific context (the offending path, the missing field, the failed condition).
  • request_id — matches X-Request-ID. Include in any support ticket.

The HTTP status matches the error class (4xx for client, 5xx for server), but specific handling should use code.

Retry classification#

Code Retry? Notes
authentication_required No Add or refresh the Authorization header.
token_expired No Refresh via OAuth client-credentials or refresh flow.
access_denied No Caller lacks permission for this action. Don't retry blindly.
mfa_required No Re-auth with MFA before retrying.
ip_not_allowed No Caller IP blocked by policy condition.
invalid_request No Fix the request body.
validation_error No details lists the failing fields.
invalid_path No Path format violates rules.
secret_not_found No Path doesn't exist.
version_not_found No Version doesn't exist or has aged out.
secret_exists No Soft-deleted path in retention.
version_conflict Rarely Concurrent write; fetch current state and retry.
policy_in_use No Detach bindings first.
rate_limited Yes Honor Retry-After.
service_unavailable Yes Transient — back off.
internal_error Once Retry once with backoff; then escalate.

Anything not listed above is generally non-retryable.

Full error catalog#

Authentication / authorization#

HTTP Code Meaning
401 authentication_required Missing or malformed Authorization header.
401 token_expired The token's exp has passed.
401 token_invalid Signature didn't validate.
401 token_revoked Token was explicitly revoked in ScaiKey.
403 access_denied No policy rule permits this action for this identity.
403 insufficient_scope The token's scopes are too narrow.
403 mfa_required Action requires MFA; the token is not MFA-backed.
403 ip_not_allowed Caller IP is outside the rule's ip_ranges.
403 time_window_violation Caller is outside the rule's time_window.
403 tenant_access_denied Explicit tenant access attempted without partner admin.

Validation#

HTTP Code Meaning
400 invalid_request Malformed JSON or top-level shape.
400 invalid_path Path violates the path format rules.
400 invalid_secret_type Unknown secret_type.
400 invalid_duration Duration string (90d, etc.) didn't parse.
400 invalid_cursor Pagination cursor is expired or malformed.
422 validation_error Field-level validation failed. details.fields lists problems.
400 invalid_policy Policy rules or bindings invalid.
400 invalid_glob Path pattern isn't a valid glob.

Not found#

HTTP Code Meaning
404 secret_not_found No secret at that path.
404 version_not_found Version doesn't exist or aged out.
404 policy_not_found
404 binding_not_found
404 webhook_not_found
404 subscription_not_found
404 rotation_policy_not_found
404 ca_not_found
404 certificate_not_found
404 csr_not_found
404 trust_anchor_not_found
404 engine_not_found
404 role_not_found
404 lease_not_found
404 tenant_not_found
404 identity_not_found
404 federation_backend_not_found

Conflict#

HTTP Code Meaning
409 secret_exists Path currently soft-deleted in retention window.
409 version_conflict Concurrent modification; refetch and retry.
409 policy_in_use Policy has active bindings; remove them first or use force=true.
409 engine_in_use Engine has active leases.
409 ca_has_certificates CA has issued certificates; revoke them first.
409 name_conflict Another resource with that name exists.
410 secret_expired expires_at has passed.

Rate limit / availability#

HTTP Code Meaning
429 rate_limited Too many requests. Retry-After tells you when.
429 quota_exceeded Hard quota reached for the tenant; not just a rate limit.
503 service_unavailable Transient dependency (DB, Redis, KMS) issue.
503 feature_disabled Feature gated off at deploy.

Server errors#

HTTP Code Meaning
500 internal_error Unexpected server error. Include request_id in a support ticket.
500 encryption_error KMS interaction failed.
500 storage_error Database or object storage error.
502 backend_error Federated backend or ACME upstream failed.
504 backend_timeout Federated backend didn't respond in time.

Validation error details#

422 validation_error responses include details.fields:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "error": {
    "code": "validation_error",
    "message": "Request validation failed",
    "details": {
      "fields": [
        {"field": "rules[0].path_pattern", "error": "required"},
        {"field": "rules[0].permissions", "error": "must include at least one permission"}
      ]
    }
  }
}

Show these to the caller verbatim.

Rate limit headers#

On any response (success or 429):

text
1
2
3
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 842
X-RateLimit-Reset: 1714478400

On 429:

text
1
Retry-After: 45

Sleep Retry-After seconds before retrying. SDKs handle this automatically.

Request IDs#

Every response includes X-Request-ID. You can also send your own X-Request-ID header on the request — ScaiVault echoes it back. Use this for distributed tracing.

When filing a support ticket, always include the request_id from the failing response.

What's next#

Updated 2026-05-17 13:26:50 View source (.md) rev 2