Search this page for the literal text you were shown. Every message here is reproduced exactly as Leed prints it, including the two with awkward grammar, because a reader pastes what they saw rather than what the sentence ought to say. The explanation lives in the next column; the string stays untouched so a search finds it.
How to read an error
Three status codes carry almost everything, and the difference between them is the difference between three completely different fixes.
- 403 is your role. The action exists, and you are not allowed to perform it. Nothing about your plan changes this; someone with a stronger role, or a resource override on that specific page or page type, has to do it or grant it to you. Privilege Matrix says which privilege each action needs.
- 402 is your plan. The action exists and your tier does not include it. This is the only class on this page a plan change resolves.
- 400, 404 and 409 are state. Something about the page, path, menu or deployment is not in a condition that allows the action — a path is taken, a page is unpublished, a version is stale, a deployment is not the newest one.
Leed keeps 402 strictly separate from 403 by design, so an upgrade prompt is never shown for a permissions problem and a permissions message is never shown for a billing one. If you are holding a status code, that split is the fastest way to know which page to read next.
In the page editor
Editor and collaboration messages
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
Unable to connect to the collaborative editing service. Please refresh the page. | Full-panel message in place of the editor | The collaborative session hit a fatal connection error | Refresh; if it persists the collab service is unreachable from your network — see Autosave, Collaboration and Locking |
Connecting… | Gray placeholder where the editor should be | The editor has not synced yet — a normal transient state | Wait a moment; if it never clears, treat it as the message above |
Your last edit wasn't saved — the page is locked for publishing. | Amber toast at the bottom of the editor, auto-clears after five seconds | A publish held the document while you typed, so that update was rejected | Wait for the publish to finish and retype the edit — Autosave, Collaboration and Locking |
Page is locked (read-only) | Tooltip on the version chip in the document header | You are viewing a published revision | Switch to the working revision — Revisions and Versions |
Spec-driven APIs are read-only. | Page settings panel | The page belongs to an api page type and its content comes from the OpenAPI spec | Change the spec and re-import — API Reference Pages |
Page version is out of date — reload and retry | 409 from a content write | Someone else’s edit landed first | Reload the page and reapply your change |
Collaborative editing is temporarily unavailable | 503 from a content write | The collab transport is not reachable from the API | Retry; this is infrastructure, not your document |
Page is locked for publishing | 409 from a content write | Same lock as the amber toast, seen from the API or an MCP client | Retry after the publish completes |
The AI assistant isn't available for your account on this page. | Empty state on the editor’s Assistant tab | The in-editor assistant session is not enabled for your account | Use the Chat workspace instead — AI in the Editor |
Analytics are only available for published pages. | Empty state on the editor’s Analytics tab | The page has never been published, so no events exist | Publish it — Page Analytics in the Editor |
Pages and page types
Page and page-type messages
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
API pages are generated from a spec and can't be edited in the CMS | 403 on any content write | The page type’s kind is api | Edit the OpenAPI spec and re-import; no role or flag lifts this |
This page type is Content Locked; existing pages are read-only. An Administrator or Content Publisher can uncheck Content Locked in Settings → Page Types to lift it. | 403 on any content write | Content Locked is set on the page type | Ask an Administrator or Content Publisher to clear it — Configuring a Page Type |
This page type is locked; no new pages can be added. | 403 when creating a page | Same Content Locked flag, on the create path | As above |
Only an Administrator or Content Publisher can lock or unlock a page type. | 403 when setting either lock | You tried to set locked or navMenuLocked without the role | Ask someone with the role — Page Type Reference |
{"error":"Missing required fields","missingFields":["summary"]} | 400 when publishing or scheduling | The page type declares required fields and one is empty | Fill the named fields; documentation page types require summary by default — Configuring a Page Type |
Published pages must be deleted through a schedule | 400 on delete | The page has been published, so removing it is a scheduled operation | Schedule the delete instead — Managing Pages |
Scheduling a delete for a non published page is unnecessary | 400 on scheduled delete | The page was never published, so it can be deleted outright | Delete it directly |
Page is not scheduled | 400 when canceling a schedule | There is no pending schedule on that page | Nothing to cancel — check the page’s status |
Page <id> not found | 404 on any page route | No page with that id in your workspace — a soft-deleted page reads the same way | Check the id; a deleted page cannot be reached by id |
Only api page types can be deleted | 400 on page-type delete | Deleting a whole set is supported only for api types | Empty the type instead of deleting it |
A page that will not publish for a missing summary is enforcing its page type’s required fields, which are set on Configuring a Page Type and enumerated with their per-kind defaults on Page Type Reference.
URLs, paths and menus
Path and menu messages
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
Path already taken | 400 when adding an alias | Another page or alias already owns that exact path | Pick a different path, or remove the alias that holds it — Aliases and Redirects |
Cannot move page: the path '…' is already in use by another page | 409 on a docs-menu save | The move would compute a folder path another page already occupies | Rename the folder or the page before moving it — Folders Set Your URLs |
Cannot move page: the path '…' is the root path of the '…' page type | 409 on a docs-menu save | A page would land exactly on another page type’s root, shadowing the whole set | Move it one level in; overlapping subtrees are allowed, an exact root collision is not |
A docs page item cannot have children — place pages inside folders instead | 400 on a docs-menu save | A page item was given a submenu | Nest with a folder — Left Navigation Menu |
Duplicate page in menu: the page is already in this menu, so the add was rejected — a page may only be referenced once, in a single docs menu | 409 on a docs-menu save, reason duplicate_in_menu | The tree references the same page twice | Remove one reference and link to it from prose instead |
A docs page may only be referenced once, in a single docs menu | 409 on a docs-menu save, reason in_other_menu | The page already lives in a different docs left-nav menu | Remove it from the other menu first |
Cannot change navigation: the '…' page type's navigation is locked. An Administrator or Content Publisher can uncheck Navigation Menu Locked in Settings → Page Types. | 403 on a docs-menu save | Navigation Menu Locked freezes that set’s URLs; presentation edits stay allowed | Ask for the lock to be cleared, or restrict yourself to icon and tooltip changes |
Conflicting menu name | 400 when creating or renaming a menu | Another menu in the workspace already has that name | Choose a different name |
<h1>documentationConfiguration is missing!</h1> | Rendered on every page of the built docs set | The merged configuration has no layoutName, so there is no layout to render | Set the five configuration values a docs set needs — Creating a Documentation Set |
Publishing and deployments
Deployment messages
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
Blocked: the preview site's latest deployment failed. Resolve the error before promoting to public. | Deploy tab, in place of the push-live control | The newest preview deployment failed, so there is nothing safe to promote | Fix and republish to preview first — When a Deployment Fails |
Blocked: the preview site is still building. Wait for it to finish. | Deploy tab, same place | A preview build is in flight | Wait for it to finish |
You don't have permission to push live. | Deploy tab hint under the push-live control | Your role lacks the promote privilege | Ask a Content Publisher or Administrator — Promoting Preview to Live |
Nothing new to push live. | Deploy tab hint | Preview and live are on the same commit | Publish something to preview first |
Only failed deployments can be retried | 400 on retry | The deployment did not fail | Nothing to retry |
This build failed due to a content/template error and must be fixed in the content | 400 on retry | The failure message starts with [site-build], so a retry would fail identically | Fix the content or template and publish again |
Only the most recent deployment for a branch can be retried | 400 on retry | You are retrying an older row | Retry the newest row on that branch |
Deployment not found | 404 on retry or detail | No deployment with that id in your workspace | Refresh the deployment list |
Build error prefixes
Whether a failed build can be retried at all is decided by the prefix on its error message, not by anything you choose. [site-build] means the failure is in your content or templates and a Retry button is deliberately not offered; every other failure is infrastructure and is retryable.
| Prefix | Phase that produced it | Retryable? | What you do |
|---|---|---|---|
[site-build] | The site build itself | No | Fix the content or template, then publish again |
[version-upload] | Uploading the built version to Cloudflare | Yes | Retry |
[upload] | Upload attempted with no build output | Yes | Retry |
| (no prefix) | Infrastructure, a timeout, or a workflow step | Yes | Retry |
Plans and quotas
Every entitlement denial in Leed — a feature gate, a quota meter, the analytics window — returns the same 402 body, so one shape covers all of them.
{
"error": "upgrade_required",
"reason": "feature_gated",
"feature": "dynamicCta",
"requiredTier": "growth",
"currentTier": "free"
}| Field | Meaning |
|---|---|
error | Always the literal upgrade_required |
reason | feature_gated (the feature is not in your tier) or quota_exceeded (you are over an allowance) |
feature | A catalog feature key, or a quota kind — contacts or analyticsRetention |
currentTier | Your workspace’s tier: free, starter, growth or enterprise |
requiredTier | The lowest tier that includes the feature; filled in automatically for feature_gated |
quota | The allowance, on quota_exceeded only |
used | What you have consumed, on quota_exceeded only |
A quota denial carries the numbers instead of a required tier:
{
"error": "upgrade_required",
"reason": "quota_exceeded",
"feature": "contacts",
"currentTier": "free",
"quota": 250,
"used": 250
}There is one case where a 400 pre-empts the 402, and it is the most misread status pairing in the product. A custom color theme, code theme or font name is shape-checked before the tier is consulted:
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
Invalid colorTheme: a custom name must be lowercase letters and numbers only, at most 32 characters. | 400 on a Settings → General or page-type save | The name you typed is not a well-formed class token. The same message appears with codeTheme and font in place of colorTheme | Remove the dashes and any other punctuation from the part you chose |
The stored value is the full prefixed class, so color-theme-leed is valid and color-theme-leed-ai is not — the leed-ai you supplied contains a dash. Because the shape check runs first, that name is a 400 on every plan, including Enterprise, never a 402 offering you an upgrade. Naming a custom theme at all is a Starter feature; the CSS behind the name is written in your repository — Custom Documentation Themes.
Signing in and account access
Sign-in and account messages
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
More than one Leed account uses a verified email from this GitHub account, so we can't tell which one you mean. … | Sign-in screen, code github_multiple_accounts | Two Leed accounts match verified GitHub emails | Sign in with a magic link, then connect GitHub from your profile |
We couldn't reach GitHub to read your account details. Please try again in a moment. | Sign-in screen, code github_email_fetch_failed | GitHub’s API did not answer | Retry shortly |
None of the email addresses on your GitHub account are verified on GitHub. … | Sign-in screen, code email_not_found | GitHub reports no verified address to match on | Verify an address on GitHub that matches your Leed account |
Your Leed account email hasn't been verified yet, so we can't link GitHub to it. … | Sign-in screen, code account_not_linked | Your Leed email is unverified, so the link is refused | Sign in once with a magic link, then connect GitHub |
GitHub sign-in only works for existing Leed accounts. … | Sign-in screen, code signup_disabled | GitHub cannot create accounts; no matching account was found | Sign in by magic link, or ask an administrator for an invitation |
This link has expired | Sign-in screen | The magic link is past its five-minute window | Request a new one |
This invitation is invalid or has expired. | Invitation screen | The invitation token does not resolve, or is past two days old | Ask for a fresh invitation |
Invitation Already Used | Invitation screen | The invitation has been accepted once already | Sign in normally |
Failed to create account. The email may already be registered. | Sign-up screen | Account creation was refused | Try signing in instead |
Invalid Domain | 400 on sign-up | The email domain is not a recognizable registrable domain | Use a work address on a real domain |
Unable to change email | 400 on a user update | Email addresses cannot be changed through this route | Contact an administrator |
No organization membership found | 403 on any authenticated call | The session resolves to no workspace membership | An administrator has to finish setting up your account |
User is not registered in this system | 403 on any authenticated call | You signed in, but no CMS user record exists for you | As above |
User is not a member of this organization | 403 on any authenticated call | A CMS user exists but carries no role in this workspace | As above |
org_selection_required | 422 | You belong to more than one workspace and none is active | Not an error to act on — the browser redirects you to the workspace picker |
For your security, connecting or disconnecting GitHub needs a recent sign-in. Sign out and back in, then try again. | Profile → Connected Accounts | The action requires a fresh session | Sign out, sign back in, retry |
The remedies behind every one of these are on Sign-In Troubleshooting, and the workspace-membership 403s in particular are explained at Joining and Switching Workspaces.
Assets
Upload messages
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
Valid file types are: png,jpeg,gif,webp,svg | Image upload modal | The file’s type is not in the accepted list for that asset kind. The list is generated per kind, so the video and audio modals print their own suffixes in the same sentence | Convert the file, or upload it as the right kind of asset — Uploading Images |
Image is 12.4MB. Images must be under 10MB. | Image upload modal | The file is not strictly under 10 MB. The figure rounds up to a tenth of a megabyte, so a file one byte over the limit reads as 10.1MB rather than 10.0MB | Compress or resize — Limits That Are Not Plan Limits |
MCP and AI clients
Three refusals can end a connection attempt, and all three arrive as a 403 whose body carries a reason.
reason | What it means | What to do |
|---|---|---|
user_banned | The account has been blocked from MCP access | Contact Leed |
no_cms_membership | The signed-in identity resolves to no CMS user, company or role | The same account-provisioning gap as the sign-in 403s above |
mcp_ineligible_tier | The workspace’s stored tier is unset or unrecognized | See the warning below |
Protocol-level failures come back as JSON-RPC error codes, each with a matching HTTP status:
| Code | Name | HTTP status | Typical cause |
|---|---|---|---|
-32700 | Parse error | 400 | The body is not valid JSON |
-32600 | Invalid request | 400 | Not a well-formed JSON-RPC message, a null request id, or a batch — Leed accepts exactly one request or notification per POST. The same code carries a rejected Origin, which is returned as 403 |
-32601 | Method not found | 404 | The client called a method this server does not implement |
-32602 | Invalid params | 400 | Required parameters are missing or malformed, including a missing _meta envelope |
-32603 | Internal error | 500 | The server failed while handling a valid call |
-32020 | Header mismatch | 400 | The protocol-version header is missing, out of charset, or names a different era than the body |
-32022 | Unsupported protocol version | 400 | The revision the client asked for is not on offer; the error names the ones that are |
A GET or DELETE against either MCP endpoint answers 405 with Allow: POST; both servers are POST-only. And a page write whose markdown uses a feature the page type disables is refused with a 400 that names both sides — This page type does not allow: alerts, tables. Allowed formatting features: code blocks. — which is explained at Formatting by Page Type.
Errors from the leed CLI
| Message | Where you see it | What it means | What to do |
|---|---|---|---|
You cannot 'commit' directly, please use: followed by leed site commit -m "update details" | git hook, exit code 18 | You ran git commit in a site repository | Commit through the CLI — Validate, Commit and Push |
You must run the following command before changes can committed: followed by leed site build | leed site commit | The working tree has not been built since your last edit. The missing “be” is verbatim | Run leed site build, then commit |
Error: Restricted file violation! | leed site validate | A changed file is one the CLI will not let you commit | Revert it — Editable and Read-Only Files |
You are only allowed on specific branches. Change back to staging! | leed site commit and leed site push | You are on a branch the CLI refuses to write from | git checkout staging — Git Workflow |
Site configuration not initialized. Run `leed site init`!!! | Any command needing a site config | There is no initialized leed.config.json here | Run leed site init — Leed Config and Files |
Remote has conflicting changes that can't be auto-rebased. | leed site push | Someone else pushed to the same branch and the rebase failed | Resolve the conflict locally, then push again |