Skip to content
Error Reference

Error Reference

Error Response Envelope

All API errors follow a consistent envelope format based on RFC 9457 (Problem Details for HTTP APIs). Every error response contains these fields:

{
  "type": "https://docs.aiffinity.me/developers/errors#invalid_schema",
  "status": 400,
  "title": "Invalid Schema",
  "detail": "The 'temperature_c' field is declared as 'string' but the schema requires 'number'.",
  "instance": "/v1/providers/packages/pkg_abc123/versions/ver_xyz789/validate"
}
Field Type Description
type string (URI) A URI reference that identifies the error type. Links to the relevant section in this documentation.
status integer The HTTP status code. Matches the response status.
title string A short, human-readable summary of the error type. Stable across occurrences.
detail string A human-readable explanation specific to this occurrence of the problem.
instance string (URI) The API path that generated the error. Useful for debugging and support tickets.

Some errors include additional fields beyond the standard envelope:

{
  "type": "https://docs.aiffinity.me/developers/errors#missing_field",
  "status": 400,
  "title": "Missing Required Field",
  "detail": "The field 'location' is required by the capability schema but was not provided.",
  "instance": "/v1/providers/packages/pkg_abc123/capabilities/current_weather/execute",
  "field": "location",
  "schema_path": "$.properties.location"
}

Validation Errors (400)

Returned when the request payload, query parameters, or capability descriptor fails validation.

Error Code Status Description
invalid_schema 400 The capability descriptor's JSON Schema is malformed or contains unsupported constructs.
missing_field 400 A required field is missing from the request body or capability response.
invalid_format 400 A field value does not match its expected format (e.g., invalid UUID, malformed URL, wrong date format).

invalid_schema — Invalid Schema

Possible causes:

Resolution:

missing_field — Missing Required Field

Possible causes:

Resolution:

invalid_format — Invalid Format

Possible causes:

Resolution:

Authentication Errors (401/403)

Returned when authentication fails or the authenticated principal lacks permission for the requested operation.

Error Code Status Description
token_expired 401 The access token has expired. Obtain a new token using your refresh token or client credentials.
insufficient_scope 403 The access token does not include the required scope for this operation.
account_suspended 403 Your developer account or the specific package has been suspended. Check the developer console for details.

token_expired — Token Expired

Possible causes:

Resolution:

// The SDK handles token refresh automatically
const client = new ProviderPlatformClient({
  clientId: process.env.AIFFINITY_CLIENT_ID,
  clientSecret: process.env.AIFFINITY_CLIENT_SECRET,
  // Token refresh is automatic — no manual handling needed
});

// Manual refresh with raw HTTP
const response = await fetch('https://api.aiffinity.me/v1/auth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'client_credentials',
    client_id: process.env.AIFFINITY_CLIENT_ID,
    client_secret: process.env.AIFFINITY_CLIENT_SECRET,
  }),
});

insufficient_scope — Insufficient Scope

Possible causes:

Resolution:

account_suspended — Account Suspended

Possible causes:

Resolution:

Rate Limit Errors (429)

Returned when your application exceeds the allowed request rate. All rate limit responses include Retry-After and X-RateLimit-* headers.

Error Code Status Description
rate_limit_exceeded 429 You have exceeded the sustained request rate for your tier. Back off and retry after the Retry-After interval.
burst_limit 429 Too many requests in a short burst window (typically 10 requests per second). Spread requests more evenly.

rate_limit_exceeded — Rate Limit Exceeded

Possible causes:

Resolution:

// Example: reading rate limit headers
const response = await fetch('https://api.aiffinity.me/v1/providers/packages', {
  headers: { 'Authorization': `Bearer ${token}` },
});

if (response.status === 429) {
  const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);
  console.log(`Rate limited. Retrying in ${retryAfter}s`);
  await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
}

// Proactive quota tracking
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0', 10);
const resetAt = new Date(parseInt(response.headers.get('X-RateLimit-Reset') || '0', 10) * 1000);
console.log(`Remaining: ${remaining}, resets at: ${resetAt.toISOString()}`);

burst_limit — Burst Limit

Possible causes:

Resolution:

Execution Errors (500/502/504)

Returned when the capability execution fails due to infrastructure or runtime issues.

Error Code Status Description
capability_timeout 504 The capability handler did not respond within the allowed timeout (default: 10 seconds).
runtime_unavailable 502 The provider's runtime endpoint is unreachable or returned a non-HTTP response.
execution_failed 500 The capability handler returned an unexpected error or the response did not match the declared schema.

capability_timeout — Capability Timeout

Possible causes:

Resolution:

runtime_unavailable — Runtime Unavailable

Possible causes:

Resolution:

execution_failed — Execution Failed

Possible causes:

Resolution:

// Robust error handling in your handler
const weatherHandler: CapabilityHandler = {
  async execute(request) {
    try {
      const weather = await fetchWeatherData(request.params.location);

      return {
        status: 'ok',
        data: {
          location: weather.city,
          temperature_c: weather.temp,
          condition: weather.condition,
        },
        ttl: 900,
      };
    } catch (error) {
      // Return a structured error instead of letting exceptions propagate
      if (error.code === 'UPSTREAM_TIMEOUT') {
        return {
          status: 'degraded',
          error: {
            type: 'upstream_timeout',
            detail: 'Weather API did not respond within 5 seconds',
            retryable: true,
          },
        };
      }

      return {
        status: 'error',
        error: {
          type: 'internal_error',
          detail: 'An unexpected error occurred',
          retryable: false,
        },
      };
    }
  },
};

Certification Errors

These errors occur during the conformance testing and submission process, not during normal API operations.

Error Code Status Description
conformance_failed 400 The package version did not pass the conformance suite. The aggregate score is below 80/100.
dimension_below_threshold 400 An individual conformance dimension scored critically low (below 5 points), indicating a fundamental issue that must be addressed regardless of the aggregate score.

conformance_failed — Conformance Failed

Possible causes:

Resolution:

dimension_below_threshold — Dimension Below Threshold

Possible causes:

Resolution:

Common Issues Troubleshooter

My package submission failed

Symptom: Calling client.packages.submit() returns a conformance_failed error even though local validation passed.

Cause: Local validation with --local (without --full) only checks 3 of 6 dimensions (schema, contracts, documentation). The submission process runs all 6 dimensions including performance, error handling, and security.

Fix: Run the full conformance suite against a running runtime: npx @aiffinity/provider-platform-sdk validate --local ./capability.json --runtime http://localhost:3000 --full

Webhook signatures don't match

Symptom: Webhook payloads arrive but your signature verification rejects them with a mismatch error.

Cause: The signature is computed over the raw request body. If your framework parses the body before you can access the raw bytes, the re-serialized JSON may differ (e.g., key ordering, whitespace).

Fix: Compute the HMAC-SHA256 signature over the raw request body bytes, not a parsed-and-re-serialized version. In Express, use express.raw({ type: 'application/json' }) on the webhook route. In Fastify, use request.rawBody.

Capability timeout in testing

Symptom: The conformance suite reports capability_timeout during performance testing, but your handler responds quickly locally.

Cause: The conformance suite adds realistic network latency. If your handler takes 8–9 seconds, the additional network round-trip pushes it past the 10-second timeout.

Fix: Aim for handler response times under 5 seconds to leave headroom for network latency. Use the trace store to identify slow steps. Add caching for upstream API calls.

Schema validation passes locally but fails remotely

Symptom: validate --local passes but the remote conformance run reports invalid_schema.

Cause: Your local SDK version may be outdated and using a different schema validation library version. The remote suite always uses the latest validation rules.

Fix: Update to the latest SDK: npm install @aiffinity/provider-platform-sdk@latest. Then re-run local validation to confirm alignment.

Rate limited during CI builds

Symptom: CI pipelines intermittently fail with rate_limit_exceeded errors.

Cause: Multiple CI runs sharing the same client_id compete for the same rate limit quota.

Fix: Create a dedicated sandbox app for CI with its own credentials. Add request throttling in your CI scripts. Use the --min-score flag to fail fast without running the full suite on every commit.

Retry Guidance

Not all errors should be retried. Use this table to determine whether to retry, fix, or escalate.

Error Code Retryable Strategy
invalid_schema Terminal Fix the schema and resubmit. Retrying will produce the same error.
missing_field Terminal Include the missing field in the request. Retrying without changes will fail.
invalid_format Terminal Correct the field format and resubmit.
token_expired Retryable Refresh the token, then retry the original request immediately.
insufficient_scope Terminal Update app scopes and obtain a new token. Retrying with the same token will fail.
account_suspended Terminal Address the suspension via the developer console. No automated retry.
rate_limit_exceeded Retryable Wait for Retry-After seconds, then retry with exponential backoff and jitter.
burst_limit Retryable Wait 1–2 seconds, then retry. Reduce request concurrency.
capability_timeout Retryable Retry once after 2–5 seconds. If it fails again, investigate the handler's performance.
runtime_unavailable Retryable Retry with exponential backoff (max 3 attempts). If persistent, check runtime health.
execution_failed Terminal Investigate the handler error via trace store. Fix the root cause before retrying.
conformance_failed Terminal Improve your package to meet the 80/100 threshold, then resubmit.
dimension_below_threshold Terminal Address the critical dimension gap, then resubmit.

Recommended backoff implementation

async function retryWithBackoff<T>(
  fn: () => Promise<T>,
  maxRetries = 3,
  baseDelay = 1000,
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error: any) {
      // Don't retry terminal errors
      const terminalTypes = [
        'invalid_schema', 'missing_field', 'invalid_format',
        'insufficient_scope', 'account_suspended',
        'execution_failed', 'conformance_failed',
        'dimension_below_threshold',
      ];

      if (terminalTypes.includes(error.type) || attempt === maxRetries) {
        throw error;
      }

      // Respect Retry-After header if present
      const retryAfter = error.headers?.['retry-after'];
      const delay = retryAfter
        ? parseInt(retryAfter, 10) * 1000
        : baseDelay * Math.pow(2, attempt) + Math.random() * 1000;

      console.log(`Attempt ${attempt + 1} failed, retrying in ${Math.round(delay)}ms`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw new Error('Unreachable');
}