Common errors
The API error codes and messages you'll actually hit — what each one means, and how to fix it.
When something goes wrong, the Alaf Server API answers with a small JSON object, not a wall of stack trace.
It always has a human error message, and for the failures worth reacting to programmatically, a stable
machine code. Validation failures add a details map that names the exact fields that were wrong.
{ "error": "This access token is read-only", "code": "TOKEN_READ_ONLY" }So when you see an error, you have two things to work with: the code (look it up in the table below) and
the HTTP status (the number your client reports — 401, 403, 429, and so on). The message tells you
what happened; the code tells you which fix applies.
The error table
Scan for the code (or status) you got. Not every error carries a code — the generic 500 and the 429
rate-limit response have none, so match those by status.
| Code / message | What it means | What to do |
|---|---|---|
VALIDATION_ERROR (400) — "Validation error" | Your request body or query didn't match what the endpoint expects. The response's details map lists each offending field and why. | Read details, correct the named fields, and resend. This is a client-side mistake — retrying the same payload won't help. |
INVALID_TOKEN (401) — "Invalid or expired access token" | The Authorization: Bearer token isn't recognized — it was mistyped, revoked, or the token no longer maps to a real user. | Create a fresh token with alaf server token create and use that. Confirm you copied the whole opsh_pat_… value. |
BEARER_NOT_ALLOWED_FROM_BROWSER (401) — "Access tokens are not allowed from browser origins" | You sent a bearer token from a browser-trusted origin. Bearer auth is for CLI and server-to-server calls only; this block stops a stolen session token being replayed past the cookie defence. | Use the token from a terminal or backend, not the browser. In the dashboard you don't need a token at all — it authenticates with your session cookie automatically. |
UNAUTHORIZED (401) — "Unauthorized" (no code on the plain form) | No valid session and no valid token — you're simply not signed in. | In the dashboard, log in again. From the API/CLI, send Authorization: Bearer <token>. See the API overview for the auth model. |
TOKEN_ORG_SCOPE (403) — "This access token is scoped to a different organization" | Your token is bound to one organization, but you sent an X-Organization-Id header naming a different one. | Drop the X-Organization-Id header, or use a token that belongs to the org you're targeting. (The MCP wording is "This authorization is scoped to a different organization".) |
TOKEN_READ_ONLY (403) — "This access token is read-only" | A read-only token was used for a mutating request (POST, PUT, PATCH, or DELETE). | Use a read-write token for writes, or switch the call to a read (GET). (The MCP wording is "This MCP authorization is read-only".) |
FORBIDDEN (403) — "Forbidden" | You're authenticated, but your role or grants in this organization don't permit the action. | Ask an org owner/admin for the right role, or check Permissions & roles for what each action needs. |
NOT_FOUND (404) — "<resource> not found" | The thing you asked for doesn't exist — or it exists but isn't in your organization (Alaf Server returns 404 rather than leaking that it's someone else's). | Double-check the id. List the resource (e.g. GET /api/projects) to get valid ids for your org. |
CONFLICT (409) — e.g. "Project '…' already exists", "Domain '…' is already in use" | Something with that name is already taken in your organization — a project name or slug, a domain/hostname, or an environment name. | Pick a different name, slug, or hostname, or reuse the resource that already exists instead of creating a duplicate. |
| Rate limited (429) — "Too many requests" (no code) | You exhausted a rate-limit bucket. Alaf Server limits the whole /api surface per rolling minute. | Honor the Retry-After header (seconds) and back off — don't hammer-retry. See rate limits for the per-policy budgets. |
AUTH_UNAVAILABLE (503) — "Authentication service unavailable" | Checking your session threw — the auth backend's database is unreachable, session decryption failed, or similar. Importantly, this is not treated as "no session" — Alaf Server fails closed rather than letting you through. | Transient — retry after a moment. If it persists, check your instance's database and API logs. |
| Internal server error (500) — "Internal server error" (no code) | An unhandled error on the server. There's no machine code because it wasn't an anticipated failure. | Check your API server logs for the [UNHANDLED ERROR] entry — that has the real cause. If self-hosting, that log line is where to start. |
The ones you'll hit first
Here are the everyday ones spelled out, with the fix step by step.
"Access tokens are not allowed from browser origins"
Your API call returns 401 with code: "BEARER_NOT_ALLOWED_FROM_BROWSER".
What it means: You sent an Authorization: Bearer token from a browser (or an origin Alaf Server trusts as
a browser front-end). Bearer tokens are meant for the CLI and server-to-server calls — the dashboard is not
supposed to carry one, so Alaf Server rejects it to stop an exfiltrated session token being replayed.
How to fix:
- If you're building against the API, move the call to a terminal or a backend service — anywhere that isn't a browser origin.
- If you were poking the API from the browser to mimic the dashboard, you don't need a token: the dashboard
authenticates with its
httpOnlysession cookie automatically. - Generate tokens for machine use only, with
alaf server token create.
"This access token is read-only" / "scoped to a different organization"
A write returns 403 with code: "TOKEN_READ_ONLY", or any call returns 403 with code: "TOKEN_ORG_SCOPE".
What it means: Tokens can be narrowed at creation. A read-only token refuses POST/PUT/PATCH/DELETE;
an org-scoped token refuses to act on a different org than the one it's bound to (which happens when your
X-Organization-Id header names another org).
Fixes: For TOKEN_READ_ONLY, create a read-write token, or make sure the call really needs to be a write.
For TOKEN_ORG_SCOPE, remove the X-Organization-Id header (the token already knows its org) or use a token
issued for the org you're targeting.
"Validation error"
A request returns 400 with code: "VALIDATION_ERROR" and a details object.
What it means: The request body or query parameters didn't match the endpoint's schema. This is always a
client-side problem — the details map pins down exactly which fields failed and why.
How to fix:
- Read the
detailsmap — its keys are the field names, and each value lists the problems with that field. - Correct just those fields (a missing required field, a wrong type, a value out of range).
- Resend. Retrying the identical payload will fail identically.
"Too many requests"
A request returns 429 with body {"error":"Too many requests"}.
What it means: You've spent a rate-limit bucket for the rolling minute. Unauthenticated traffic is limited per IP; authenticated traffic gets a larger per-user budget; a few route groups (login, webhooks, MCP) have their own policies.
How to fix: Read the Retry-After response header (seconds until the window resets) and wait that long
before retrying. Every response also carries X-RateLimit-Limit, X-RateLimit-Remaining, and
X-RateLimit-Reset so you can pace yourself before you hit the wall. The per-policy limits are listed in the
API overview.
Self-hosting behind a proxy?
If you get 400 with "Missing client IP — request must come through the proxy", your instance couldn't work
out the caller's IP for its per-IP limits. That means requests are reaching the API without going through the
reverse proxy that sets the forwarded-IP header. Route traffic through your proxy (openresty in the standard
topology) rather than hitting the API port directly.
Build and deploy failures
The codes above are about the API request itself. If a deployment failed — the build screen went red, the app won't start, a port is taken — that's a different set of symptoms.
Troubleshooting deployments
Build failures, wrong ports, missing env vars, and other deploy-time problems.
API overview
The full auth model, permissions, rate limits, and error shape.
Tokens & access
Create, scope, and revoke the personal access tokens the API uses.
Permissions & roles
What owner, admin, member, and restricted roles can each do.