⚠️ Work in progress — createCMS is pre-1.0 and not production-ready (not tested in production). Expect breaking changes.
createCMS
Reference

Error codes

The CMS error codes, and how to detect them.

The CMS throws typed errors (CMSError, which extends better-call's APIError). Each has a stable code, an HTTP status, and a default message. Codes are defined in CMS_ERRORS (see packages/cms/src/core/errors.ts). Plugins add their own codes, merged into cms.$ERROR_CODES.

Detecting errors

import { isCMSError, getCMSErrorCode } from '@createcms/core';

try {
  await cms.api.pages.publishBranch({ body: { rootId, branchId } });
} catch (err) {
  if (isCMSError(err, 'PUBLICATION_APPROVAL_REQUIRED')) {
    // handle this specific case
  }
  const code = getCMSErrorCode(err); // CMSErrorCode | undefined
}
FunctionSignaturePurpose
isCMSError(error, code?) => error is CMSAPIErrorNarrow an unknown error, optionally to one code.
getCMSErrorCode(error) => CMSErrorCode | undefinedRead the code off an error.
CMSErrornew CMSError(code, overrides?)Construct or throw a CMS error by code.

These helpers work server-side, where errors are APIError / CMSError. The browser client throws a CMSClientError (a plain Error, not APIError), which isCMSError / getCMSErrorCode do not recognize. Detect it by its cmsCode:

import { CMSClientError } from '@createcms/core';

try {
  await cmsClient.pages.publishBranch({ body: { rootId, branchId } });
} catch (err) {
  if (err instanceof CMSClientError && err.cmsCode === 'PUBLICATION_APPROVAL_REQUIRED') {
    // handle this specific case
  }
}

Blocks and roots

CodeStatusMessage
ROOT_NOT_FOUND404Root block not found in snapshot
BLOCK_NOT_FOUND404Block not found in snapshot
PARENT_NOT_FOUND404Parent block not found
BLOCK_NOT_ALLOWED_IN_PARENT400Block type is not allowed inside the target parent (violates the collection's structure rules or the parent's allowChildren)
PROTECTED_BRANCH403A direct content mutation was attempted on a published branch while branchProtection.protectPublishedBranches is enabled (edit via a separate branch + merge, or unpublish first)
COMMIT_MESSAGE_REQUIRED400A content mutation was made with no message while forceCommitMessage is enabled
COMMIT_NOT_FOUND404Commit not found
EMPTY_SNAPSHOT400Empty snapshot — no versions found
BLOCK_ALREADY_DELETED400Block is already deleted
TYPE_MISMATCH400Block type does not match the expected type
ROOT_HAS_CHILDREN400Cannot delete a page that has child pages; archive or move the children first
ROOT_IN_USE409Cannot delete: this root is embedded as a reusable block on live pages; remove those references first
CANNOT_MOVE_ROOT400Cannot move the root block
CANNOT_MOVE_INTO_SELF400Cannot move an item into itself
CANNOT_MOVE_INTO_DESCENDANT400Cannot move an item into its own descendant
CIRCULAR_REFERENCE400Cannot move a page under itself or one of its descendants
PARENT_ROOT_NOT_FOUND404Parent root not found in this collection
REFERENCE_DEPTH_EXCEEDED422Reference nesting is too deep (a reusable block embeds others past the limit)
MISSING_TARGET_PROPERTIES400targetProperties is required when duplicating a root

Branches

CodeStatusMessage
BRANCH_NOT_FOUND404Branch not found
BRANCH_NAME_ALREADY_EXISTS400A branch with this name already exists for this root
CANNOT_RENAME_MAIN_BRANCH400The main branch cannot be renamed
CANNOT_DELETE_MAIN_BRANCH400The main branch cannot be deleted
BRANCH_HAS_PUBLICATIONS400Cannot delete a branch that has active publications
BRANCH_HAS_OPEN_MERGE_REQUESTS400Cannot delete a branch that is part of open merge requests
BRANCHES_NOT_SAME_ROOT400Source and target branches must belong to the same root
NO_COMMON_ANCESTOR400The two branches share no common ancestor

Merge requests

CodeStatusMessage
MERGE_REQUEST_NOT_FOUND404Merge request not found
MERGE_REQUEST_NOT_OPEN400Merge request is not open
MERGE_REQUEST_NOT_CLOSED400Merge request is not closed
MERGE_REQUEST_ALREADY_MERGED400Merge request has already been merged and cannot be reopened
MERGE_REQUEST_ALREADY_EXISTS400An open merge request already exists for this source and target branch
MERGE_REQUEST_OUTDATED400Merge request is outdated because the source branch changed after it was opened
UNRESOLVED_CONFLICTS400Cannot merge: there are unresolved conflicts
CONFLICT_NOT_FOUND404Merge conflict not found
RESOLVED_VERSION_NOT_FOUND404The provided resolvedVersionId does not reference an existing block version

Approvals

CodeStatusMessage
APPROVAL_NOT_FOUND404Approval not found
APPROVAL_ALREADY_REQUESTED400An approval has already been requested from this reviewer
APPROVAL_NOT_PENDING400Approval is not pending
APPROVAL_REVIEWER_MISMATCH403Only the requested reviewer can approve or reject this request
APPROVAL_STALE400Approval is stale: the branch has advanced past the approved commit
MERGE_APPROVAL_REQUIRED400Cannot merge: approval is required before execution
PUBLICATION_APPROVAL_REQUIRED400Cannot publish: approval is required before publication
APPROVALS_NOT_FULLY_APPROVED400Cannot proceed: not all requested approvals are approved

Publications, slugs, and redirects

CodeStatusMessage
PUBLICATION_NOT_FOUND404Publication not found for this branch
PUBLISHED_CONTENT_NOT_FOUND404No published content found
AMBIGUOUS_SLUG400Multiple roots match this slug — use rootId for an unambiguous lookup
SLUG_ALREADY_EXISTS409A root with this slug on this collection with this parentRootId already exists
SLUG_NOT_ENABLED400This collection does not have slugs enabled
SLUG_EMPTY_NOT_ALLOWED400Empty slug is not allowed for this collection (allowRoot is false)
SLUG_GENERATION_FAILED500Failed to generate a unique slug after maximum attempts
NESTING_NOT_ENABLED400parentRootId is not allowed — this collection does not have nested pages enabled
REDIRECT_NOT_FOUND404Redirect not found
REDIRECT_INVALID400A redirect endpoint must be a page (rootId) or a path, matching its type
REDIRECT_SOURCE_EXISTS409An active redirect already exists for this source

Media and assets

CodeStatusMessage
ASSET_NOT_FOUND404Asset not found
ASSET_ACCESS_DENIED403This asset is private and requires authentication
FOLDER_NOT_FOUND404Folder not found
FOLDER_HAS_CONTENT400Cannot delete folder that contains assets or subfolders
TOO_MANY_FILES400Too many files in upload batch
FILE_TOO_LARGE400One or more files exceed the maximum allowed size
INVALID_FILE_TYPE400One or more files have a disallowed MIME type
UPLOAD_FAILED500Server-side upload to S3 failed
MISSING_REQUIRED_S3_PARAMETERS400Missing required S3 parameters: hostname, accessKeyId, or secretAccessKey
UNKNOWN_S3_PROVIDER400Unknown S3 provider specified

Variables and templates

CodeStatusMessage
VARIABLE_NOT_FOUND404Variable not found
VARIABLE_KEY_EXISTS409A variable with this key already exists
VARIABLE_IN_USE409Cannot delete variable: it is still in use
TEMPLATE_NOT_FOUND404Template not found
TEMPLATE_PROPERTY_INVALID400The template's propertyKey does not exist on the block type, or is not a text property (string / richText)
TEMPLATE_KEY_EXISTS409A template for this collection/block/property combination already exists

Comments

CodeStatusMessage
COMMENT_THREAD_NOT_FOUND404Comment thread not found
COMMENT_THREAD_ALREADY_RESOLVED400Comment thread is already resolved
COMMENT_THREAD_NOT_RESOLVED400Comment thread is not resolved
COMMENT_MESSAGE_NOT_FOUND404Comment message not found
COMMENT_MESSAGE_DELETED400Comment message has been deleted
COMMENT_BODY_REQUIRED400Body is required for comment messages
COMMENT_AUTHOR_MISMATCH403Only the author can edit or delete this message

Notifications and system

CodeStatusMessage
NOTIFICATION_NOT_FOUND404Notification not found
NOTIFICATION_RECIPIENT_MISMATCH403You can only access your own notifications
USER_ID_REQUIRED400userId is required for this route when neither the request nor middleware provides one
DATA_RETENTION_NOT_CONFIGURED400dataRetention is not configured for this CMS instance

Plugins add their own codes (for example TENANT_SLUG_REQUIRED, OPTIMIZATION_FAILED). See each plugin page.

On this page