> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userepo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> HTTP status codes Repo returns and what they mean.

All errors are returned as JSON with a top-level `error` field — plus structured fields when they help.

```json theme={null}
{ "error": "Human-readable message" }
```

## Status code catalog

| Code  | Meaning               | When                                                              |
| ----- | --------------------- | ----------------------------------------------------------------- |
| `200` | OK                    | Successful read or idempotent write                               |
| `201` | Created               | New resource created (key, request, sync run)                     |
| `202` | Accepted              | Async work queued (sync run)                                      |
| `204` | No Content            | Successful CORS preflight                                         |
| `302` | Found                 | OAuth redirect to provider                                        |
| `400` | Bad Request           | Validation failed, missing params, malformed OAuth state          |
| `401` | Unauthorized          | Missing or invalid bearer token                                   |
| `402` | Payment Required      | No active subscription (paywalled tiers only)                     |
| `403` | Forbidden             | Authenticated but lacking the required scope, role, or tier limit |
| `404` | Not Found             | Resource doesn't exist or you don't have access to see it         |
| `409` | Conflict              | e.g. revoking the key currently in use                            |
| `429` | Too Many Requests     | Rate limit OR credit budget exceeded                              |
| `500` | Internal Server Error | Repo bug or DB failure — file a report                            |
| `502` | Bad Gateway           | Upstream OAuth provider or LLM error                              |
| `503` | Service Unavailable   | A required service isn't configured (e.g. Stripe in dev)          |

## Common error shapes

### Quota exceeded (Builder tier)

```json theme={null}
{
  "error": "quota_exceeded",
  "message": "This organization has used its monthly credit budget (5,000). Upgrade in /console/billing to continue.",
  "tier": "builder",
  "creditsUsed": 5000,
  "creditsIncluded": 5000
}
```

Builder tier hard-blocks at the cap. Upgrade to Studio (overage allowed) or wait for the next billing cycle.

### Rate limit exceeded

```json theme={null}
{
  "error": "Rate limit exceeded",
  "action": "search",
  "limit": 60,
  "retryAfterSeconds": 47,
  "resetAt": "2026-05-30T20:15:00Z"
}
```

Plus headers:

```http theme={null}
Retry-After: 47
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 2026-05-30T20:15:00Z
```

Honor `Retry-After` — back off with jitter rather than hammering.

### Subscription inactive

```json theme={null}
{
  "error": "subscription_inactive",
  "message": "This organization does not have an active subscription. Visit /console/billing to subscribe."
}
```

Sent on `402` when an org's subscription is `canceled`, `unpaid`, or `incomplete_expired`. Internal/enterprise tiers never see this.

### Tier limit reached (agent/connector)

```json theme={null}
{
  "error": "agent_limit_reached",
  "message": "Your builder plan allows 2 agents. Upgrade to add more.",
  "tier": "builder",
  "limit": 2,
  "current": 2
}
```

Same shape for `connector_limit_reached`.

### Invalid OAuth state

```json theme={null}
{ "error": "OAuth state expired" }
```

Possible reasons: state was issued more than 10 minutes ago, was tampered with, was issued for a different provider, or was forged. Restart the OAuth flow from the console.

### Provider errors (502)

```json theme={null}
{ "error": "OAuth exchange failed: invalid_grant" }
```

These pass through the upstream provider's error message when available. Common causes: revoked tokens, expired refresh tokens, provider API downtime.

## Idempotency

`/v1/ingest` is idempotent on `(organizationId, provider, externalId)` — re-posting the same document is a no-op (counted in `skipped`).

`/v1/sync-runs` enforces "at most one active run per connector" at the DB level — duplicate queue attempts return the existing run with `alreadyActive: true`.

Other endpoints (`/v1/search`, `/v1/context`, `/v1/ask`) are not idempotent — each call consumes a credit. If you retry, you'll burn an extra credit.
