Aira

Troubleshooting

Common errors, their causes, and how to fix them — plus debugging tools built into every Aira deployment.

Quick diagnostics

Before diving into specific errors, run these two checks:

# 1. Is the server healthy?
curl https://your-domain/api/v1/health

# 2. Is your API key valid?
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer aira_live_..." \
  https://your-domain/api/v1/health
# 200 = valid, 401 = invalid/expired

If /health returns 200, the API server, database, and signing service are all operational. If it returns anything else, the issue is infrastructure — not your code.

Common errors

POLICY_DENIED (HTTP 403)

The action was blocked by one or more policy rules.

Symptoms:

{
  "error": {
    "code": "POLICY_DENIED",
    "message": "Action blocked by policy: 'no-pii-in-prompts'",
    "details": {
      "policy_id": "pol_abc123",
      "rule": "no-pii-in-prompts"
    }
  }
}

Fix:

  1. Check which policies are active: go to Dashboard > Policies or call GET /api/v1/policies.
  2. Review the details.policy_id to find the specific rule that fired.
  3. Either adjust your action payload to comply with the policy, or update the policy rules if the block is unintended.

POLICY_DENIED is not an error — it means Aira is working correctly. The action was intentionally blocked because it violated a rule you (or your org admin) configured.

401 Unauthorized

Your API key is missing, expired, or invalid.

Common causes:

  • The key was revoked or rotated in the dashboard.
  • You are using a test key (aira_test_...) against the production API, or vice versa.
  • The Authorization header is malformed (must be Bearer aira_live_...).

Fix:

  1. Go to Dashboard > API Keys and check the key status.
  2. If expired, generate a new key and update your environment variable.
  3. Verify the header format:
# Correct
curl -H "Authorization: Bearer aira_live_abc123..." ...

# Wrong — missing "Bearer" prefix
curl -H "Authorization: aira_live_abc123..." ...

403 Forbidden

You are authenticated but lack permission for this action.

Common causes:

  • Your API key belongs to a different organization than the resource you are accessing.
  • Your role (viewer, member) does not have write access to the endpoint.
  • The resource belongs to a different sub-product and your key is scoped.

Fix:

  1. Confirm your org ID matches the resource: GET /api/v1/health returns your org context.
  2. Check your role in Dashboard > Team.
  3. If using scoped keys, verify the key has access to the sub-product in question.

429 Too Many Requests

You have exceeded the rate limit for your plan.

Symptoms:

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Retry after 2 seconds."
  }
}

Fix:

Implement exponential backoff. Both SDKs handle this automatically when configured:

# Python SDK — built-in retry with backoff
from aira import Aira

client = Aira(
    api_key="aira_live_...",
)
// TypeScript SDK — built-in retry with backoff
import { Aira } from "aira-sdk";

const aira = new Aira({
  apiKey: "aira_live_...",
});

If you are hitting limits consistently, check your plan quotas at Dashboard > Usage or contact support to upgrade.

model_error in cases

The AI model returned invalid or unparseable JSON when evaluating a case.

Common causes:

  • A custom model endpoint is returning non-JSON responses.
  • The model is returning JSON that does not match the expected schema.
  • Network issues between Aira and the model provider.

Fix:

  1. Check the case detail in the dashboard — the raw model response is logged.
  2. If using a custom model endpoint, verify it returns valid JSON by testing directly:
curl -X POST https://your-model-endpoint/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"your-model","messages":[{"role":"user","content":"test"}]}'
  1. Verify the model endpoint is listed in Dashboard > Models and is reachable from Aira.

Webhook delivery failures

Aira retries failed webhook deliveries with exponential backoff (up to 5 attempts). If all retries fail, the webhook is marked as failed in the dashboard.

Common causes:

  • Your endpoint is unreachable (DNS, firewall, or the server is down).
  • Your endpoint does not return a 2xx status within 10 seconds.
  • TLS certificate issues (expired cert, self-signed cert without configuration).

Fix:

  1. Check Dashboard > Webhooks for delivery logs and error messages.
  2. Test your endpoint manually:
curl -X POST https://your-webhook-url \
  -H "Content-Type: application/json" \
  -d '{"test": true}'
  1. Ensure your endpoint responds with HTTP 200 within 10 seconds.
  2. For TLS issues, verify your certificate chain is complete and not expired.
  3. If developing locally, use a tunnel like ngrok to expose your endpoint:
ngrok http 8000
# Use the https://...ngrok.io URL as your webhook endpoint

Webhook payloads include a signature header (X-Aira-Signature). Always verify this signature to ensure the payload was sent by Aira. See the Webhook Verification guide.

Debugging tools

/health endpoint

Every Aira deployment exposes a health endpoint that returns server status, version, and component health:

curl https://your-domain/api/v1/health | python -m json.tool
{
  "status": "healthy",
  "version": "1.4.0",
  "components": {
    "database": "healthy",
    "signing": "healthy"
  }
}

Use this to confirm your deployment is running and which version is active.

Swagger UI

Every Aira deployment includes interactive API documentation at /docs. Open it in your browser to:

  • Browse all available endpoints.
  • Send test requests directly from the UI.
  • Inspect request/response schemas.
https://your-domain/docs

Audit log

Every action, policy change, and team membership change is recorded in the audit log. Use it to trace what happened and when:

curl -H "Authorization: Bearer aira_live_..." \
  "https://your-domain/api/v1/audit-logs?limit=20"

You can also browse the audit log in Dashboard > Audit Log.

Verifying a receipt

If you need to confirm a receipt is genuine and has not been tampered with:

from aira import Aira

client = Aira(api_key="aira_live_...")
result = client.verify_action(action_uuid="rec_abc123")

print(result.valid)        # True if signature and data are intact
print(result.timestamp)    # RFC 3161 timestamp
print(result.action_uuid)  # The action this receipt covers
import { Aira } from "aira-sdk";

const aira = new Aira({ apiKey: "aira_live_..." });
const result = await client.verify("rec_abc123");

console.log(result.valid);      // true if signature and data are intact
console.log(result.timestamp);  // RFC 3161 timestamp
console.log(result.actionUuid); // The action this receipt covers

Still stuck?

On this page