Error reference

Complete catalog of error codes, HTTP status codes, and error response format for the EmuView API.

#Error reference

Every EmuView API error returns a consistent JSON envelope. This page documents the response format and every error code the API can return.

#Error response format

{
	"error": "error_code",
	"message": "Human-readable description of what went wrong.",
	"details": {},
	"requestId": "8f1c0deadbeef123-SYD"
}
Field Type Description
error string Machine-readable error code (e.g., not_found, forbidden)
message string Human-readable message with context about the failure
details object|null Structured details for validation errors (field-level error messages)
requestId string The id the server logged this request under

#requestId

Every error body carries the id the gateway logged that request under — Cloudflare's cf-ray where there is one, a generated ULID off-platform. The same string appears in the server's [gateway:error] line, so quoting it in a bug report is what turns "the API returned a 500 yesterday" into one log line.

It is on every error status, not only 5xx: a 403 or a 404 that turns out to be a bug is exactly the report that needs tracing. It is not a secret — Cloudflare already returns cf-ray as a response header on every request it serves.

#Validation error details

When the error code is validation_error, the details field contains per-field error information:

{
	"error": "validation_error",
	"message": "One or more fields failed validation.",
	"details": {
		"fields": {
			"title": "Title is required.",
			"price": "Price must be greater than 0.",
			"email": "Invalid email format."
		}
	}
}

#SDK error handling

The SDK throws ApiError objects with typed properties:

import { ApiError } from '@emuview/sdk';

try {
	await sdk.collection('products').create({ title: '' });
} catch (err) {
	if (err instanceof ApiError) {
		console.error(err.code); // "validation_error"
		console.error(err.message); // "One or more fields failed validation."
		console.error(err.status); // 422
		console.error(err.details); // { fields: { title: "Title is required." } }
	}
}

#HTTP status codes

Status Meaning
200 OK — successful read or update
201 Created — successful resource creation
202 Accepted — async operation started (automation flows)
204 No Content — successful deletion with no body
400 Bad Request — invalid input, missing fields, or limit exceeded
401 Unauthorized — missing or invalid authentication
403 Forbidden — insufficient permissions
404 Not Found — resource does not exist
409 Conflict — resource already exists or concurrent edit
412 Precondition Failed — optimistic concurrency check failed
422 Unprocessable Entity — field validation errors
429 Too Many Requests — rate limited
500 Internal Server Error
503 Service Unavailable

#Error code catalog

#Authentication errors (401)

Code Message
unauthorized A valid Bearer token or session cookie is required.

#Authorization errors (403)

Code Message
forbidden Insufficient permissions for this action.
entitlement_required This capability is not included in your plan.
mfa_required This role requires Multi-Factor Authentication.
account_banned This account has been banned.
install_needs_person A blueprint install needs a person; this API key has no bound user.
crew_needs_person Creating a crew needs a person — its creator becomes its first admin member.
upload_needs_person An upload needs a person — a file records its uploader as its owner.
signup_forbidden Registration is not permitted.
validation_rule_failed The data violates a permission validation rule.
blocked_by_automation Blocked by automation.

The three *_needs_person codes are not permission errors, and the distinction is why they are separate codes: the caller is an API key with no bound user, so the fix is a different credential — the dashboard, or a delegated key — never a broader grant. They are returned before the permission check's own forbidden would be, so the two never arrive together. Every other write an API key makes is unaffected; these three endpoints record their caller as an owner, and an ownerless row would be unusable rather than merely unattributed.

#Validation errors (400)

Code Message
invalid_json Request body must be valid JSON.
invalid_request Invalid request parameters.
invalid_name Name contains invalid characters or is too short.
invalid_field One or more fields are invalid.
reserved_name This name is reserved by the system.
reserved_field This field name is reserved by the system.
missing_field A required field is missing.
limit_exceeded Request exceeds allowed limits.
duplicate_field A field with this name already exists.
invalid_input Invalid input provided.
invalid_mode Invalid mode specified.
invalid_column Invalid column name.

#Validation errors (422)

Code Message
validation_error One or more fields failed validation.

#Resource errors (404)

Code Message
not_found Resource not found.
collection_not_found Collection not found.
record_not_found Record not found.
database_not_found Database not found.
user_not_found User not found.

#Conflict errors (409)

Code Message
already_exists A resource with this identifier already exists.
conflict Conflicting update detected.

#Precondition errors (412)

Code Message
precondition_failed Record has been modified by another process.

#Rate limiting (429)

Code Message
rate_limited Too many requests. Please retry after the indicated time.

#Server errors (500/503)

Code Message
internal_server_error An internal error occurred.
ddl_error Database schema operation failed.
auth_error Auth handler error.
service_unavailable Service temporarily unavailable.
kv_unavailable KV namespace not configured.

#Rate limiting

Auth endpoints (/api/auth/*) are rate-limited to 5 requests per minute per IP address. When rate limited, the response includes a Retry-After header indicating how many seconds to wait.

{
	"error": "rate_limited",
	"message": "Too many requests. Please retry after the indicated time."
}

#Failure modes

Endpoint type On rate limiter unavailability Rationale
/api/auth/* Fail closed — request rejected with 429 Brute-force attacks must not bypass rate limits
All other endpoints Fail open — request allowed through Availability is preferred over perfect rate limiting

#Common error scenarios

#Missing authentication

Request: Any authenticated endpoint without an Authorization header.

{
	"error": "unauthorized",
	"message": "A valid Bearer token or session cookie is required."
}

Fix: Include Authorization: Bearer <token> in the request header.

#Permission denied

Request: An endpoint the user's role does not have access to.

{
	"error": "forbidden",
	"message": "Insufficient permissions for this action."
}

Fix: Check the user's role and the collection's access control policy. Admins can update policies in Settings → Roles & Permissions.

#Record version conflict

Request: An update with a stale version token.

{
	"error": "precondition_failed",
	"message": "Record has been modified by another process."
}

Fix: Fetch the latest record, re-apply your changes, and retry with the updated updated_at value.