standards
ErrorsConcepts

Errors

Read one error envelope everywhere, branch on its code, and know how each door reports it.


Every failed request answers with the same body. Branch on code; fall back to statusCode for coarse categories. Keep the x-request-id header when you report a problem.

The error envelope

A lookup of a missing record returns:

{
  "success": false,
  "statusCode": 404,
  "message": "Record \"abc123\" not found.",
  "code": "SCHEMA_RECORD_NOT_FOUND"
}
FieldDescription
successAlways false for errors.
statusCodeThe HTTP status, mirrored in the body.
messageA human-readable explanation. Every 5xx message is masked to Internal server error.
codeA stable machine-readable code. Absent when the request body failed validation.

When request-body parsing fails, message is Validation failed, no code is set, and an errors array points at each invalid field. path is an array because it can point into nested fields:

{
  "success": false,
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [{ "path": ["limit"], "message": "Expected number, received string" }]
}

A value that fails its attribute's type or constraints is a different case: it answers SCHEMA_VALIDATION_FAILED, with a code.

Request ids

Every response, success or error, carries an x-request-id header holding a UUID that identifies that exact request on the server side:

x-request-id: 4b2f1c9e-8a3d-4f6b-9c1e-2d7a5e8b0c4f

It is the only response header the API promises. Include it when reporting an issue.

Error codes

The codes you can meet from the SDK, the CLI and MCP:

CodeHTTPMeaning
SCHEMA_VALIDATION_FAILED400Input failed schema validation. Also refuses revoking the last Owner credential.
SCHEMA_INVALID_OBJECT_NAME400The object name is malformed.
SCHEMA_RESERVED_OBJECT_NAME400The object name belongs to a framework-native object (skill, memory, drives, artifact, meeting).
SCHEMA_INVALID_ATTRIBUTE_NAME400An attribute name is malformed.
DOCUMENT_MIME_NOT_ACCEPTED400The file matches no entry of the document attribute's accepts list.
DOCUMENT_MULTIPLE_NOT_ALLOWED400The document attribute takes a single file.
DOCUMENT_FILE_TOO_LARGE400The file exceeds the document attribute's maxFileSize.
SCHEMA_FORBIDDEN403The actor lacks permission. The message never names what was refused.
SCHEMA_ACTOR_CONTEXT_REQUIRED403No authenticated actor reached the handler.
SCHEMA_PROTECTED_OBJECT403The object is system-protected.
SCHEMA_PROTECTED_ATTRIBUTE403The attribute is system-protected.
SCHEMA_SYSTEM_ENTITY_IMMUTABLE403A system entity, such as a built-in role, cannot be modified.
SCHEMA_WORKSPACE_INVARIANT403A workspace rule refuses the write. The message names the remedy.
SCHEMA_RECORD_NOT_FOUND404No record with that id.
SCHEMA_OBJECT_NOT_FOUND404No object with that name.
SCHEMA_ATTRIBUTE_NOT_FOUND404No such attribute.
SCHEMA_SOURCE_NOT_FOUND404No schema source with that id.
SCHEMA_ROLE_NOT_FOUND404No such role.
DOCUMENT_NOT_FOUND_FOR_OPERATION404The target document does not exist.
SCHEMA_TIMEOUT408The operation timed out. Retry after backing off.
SCHEMA_DUPLICATE_OBJECT409An object with that name already exists, or is owned by core, a bundle or another source.
SCHEMA_DUPLICATE_ATTRIBUTE409An attribute with that name already exists.
SCHEMA_DUPLICATE409A view with that name is owned by another source.
SCHEMA_CONFLICT409The request conflicts with current state.
SCHEMA_OBJECT_REFERENCED409The object is still the target of relations on other objects. Drop those relation attributes first.
SCHEMA_SYNC_CONFLICT409A declaration cannot be reconciled with what the workspace already holds, such as a runtime attribute whose type clashes with the code. Relax the constraint, migrate the values, or rename the declaration.
SCHEMA_SYNC_FAILED500A sync stopped partway. The message is masked; use the request id.
SCHEMA_DESTRUCTIVE_NOT_ALLOWED500A sync would drop data and no opt-in allows it. The message is masked; use the request id.
SCHEMA_ACCESS_DENIED500Deleting a file someone else uploaded. The message is masked.
CONFIGURATION_REQUIRED503An optional capability is not wired on this deployment. Permanent: do not retry.

The HTTP status derives from the code. A code without an explicit mapping answers 500.

SCHEMA_FORBIDDEN is deliberately vague

A 403 carrying SCHEMA_FORBIDDEN always reads You do not have permission to perform this action. The envelope never names the object or the action, because the message reaches end users who have no access to those names. Branch on the code, not on the sentence. The other 403 codes are refusals a permission grant would not lift, so each keeps a message naming the remedy.

Rate limits

The hosted API counts requests per client IP in five buckets, each per minute:

BucketRoutesPer minute
DefaultRecords, schema, keys, and every route not listed below. A per-object record search is a list read and counts here.100
UploadFile uploads (POST under /files, and /upload routes).20
Global search/search and /global-search, cross-object queries.30
Bulkbulk-create, bulk-update, bulk-delete.10
AIAgent chat and streaming.5

Pushing a schema source (PUT /schema/sources/:id) is exempt: a CI run carries a whole schema in one call.

Exceeding a limit returns a 429 in the same envelope, without a code:

{ "success": false, "statusCode": 429, "message": "ThrottlerException: Too Many Requests" }

No rate-limit or retry-after header is promised. x-request-id is the only guaranteed header. Treat a 429 as transient: back off and retry.

How each door surfaces an error

DoorShapeNotes
SDKStandardsRequestError with status and code; StandardsAuthError for 401 and 403.status: 0 means a timeout or a refused connection, message Could not connect to <baseUrl>. The errors[] array and the x-request-id header are dropped; only message and code survive.
CLI✗ Error (status): message on stderr, exit code 1.exit code 2 when no instance is configured: ✗ Error: No Standards instance configured. Run "standards login" or pass --api-key.
MCPJSON-RPC -32602 for an unknown tool, or a tool your key or scopes withheld.Inside a call, the result carries isError: true and a text content Access denied: not authorized to <action> "<object>".
import { createStandards, StandardsRequestError } from "@stndrds/client";

const standards = createStandards({
  baseUrl: "https://api.standards.new/v1",
  apiKey: process.env.STANDARDS_API_KEY!,
});

try {
  await standards.from("contacts").get("abc123");
} catch (error) {
  if (error instanceof StandardsRequestError && error.status === 0) {
    // Timeout or refused connection: the API was never reached.
  }
  if (error instanceof StandardsRequestError && error.code === "SCHEMA_RECORD_NOT_FOUND") {
    // Branch on the code, not on the message.
  }
  throw error;
}

Handling errors

Branch on code for precise handling. Fall back to statusCode for categories: 4xx means the request is wrong, so fix it before retrying; 5xx is server-side and safe to retry with backoff. 408 and 429 are safe to retry as-is after backing off. CONFIGURATION_REQUIRED is the one 5xx not worth retrying: the capability is absent from the deployment, and the answer will not change.

Next steps

  • SDK errors: the error classes, SchemaSourceConflictError, and what a sync reports.
  • Workspaces and API keys: why a 403 says nothing and how to grant the missing action.
  • CLI: exit codes, output formats and the --instance flag.
  • MCP: how an agent sees a withheld tool and a refused call.