> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.docs.xano.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Warning and error codes

> Every code the CLI and the build emit, with the first sentence of the message it comes with. Match on the code, never on the message text: messages are reworded, codes are not.

## Error codes

`error.code` of a failure document (`--json`, or any piped run): `{ ok: false, error: { code, message, exitCode, details? } }`.

| Code | Meaning |
| - | - |
| `SDK_BRANCH_LIVE` | The branch is the live one and cannot be deleted or replaced that way. Exit 2. |
| `SDK_BRANCH_TAKEN` | The branch label is already in use. Exit 2. |
| `SDK_CONSTRAINT_VIOLATION` | The workspace's rows break a unique index, required column or reference the release declares; nothing landed (`details.constraint`). Exit 2. |
| `SDK_CREDENTIAL_REJECTED` | The instance rejected the credential (`details`: `{ profile, credentialType, instance, workspaceId, signIn }`). |
| `SDK_DRIFT` | A committed artifact (`xano.lock`, `.env.example`, `routes.gen.ts`) is out of date with the source — `--check`, `--strict`, `--frozen-lock`. |
| `SDK_ERROR` | Any failure without a code of its own; `exitCode` says which kind. |
| `SDK_EXPORT_INVALID` | The workspace does not build: `details.diagnostics[]` lists every error (and, under `--strict`, every warning). |
| `SDK_IDENTITY_CONFLICT` | A landing would delete or re-create an object under another identity; nothing was written (`details.refused`). Exit 2. |
| `SDK_IMPORT_REFUSED` | The target refused the import (`details.refused` names the check); exit 8 when another import was running. |
| `SDK_KIND_CONFLICT` | A name the target holds as another kind of object; nothing was written. Exit 2. |
| `SDK_LIVE_BRANCH_MISMATCH` | The live branch is not the one the command expected (`details.conflictsWith`). |
| `SDK_PRUNE_OUT_OF_SCOPE` | A landing would delete objects another source landed (`details.refused: "pruneOutOfScope"`). Exit 2. |
| `SDK_RELEASE_FILES_NOT_CARRIED` | The release cannot carry the files (hosted files, static assets) the source needs. |
| `SDK_RELEASE_NAME_TAKEN` | A release with that name already exists. Exit 2. |
| `SDK_SEED_IN_STATIC` | A static build carries seed values from non-public columns (`details.leaks[]`); nothing was published. |
| `SDK_SHARED_SCHEMA_CHANGE` | A promote would alter tables live serves from (`details.reason: "shared-schema-changes"`, `details.changes[]`), or could not read them (`"tables-unreadable"`); `--allow-shared-schema-changes` lands it. Exit 2. |
| `SDK_USAGE` | The input is wrong — a command line, a def or a value the build or the command refuses as written — a confirmation was needed off a terminal (`details.reason: "needs-confirmation"`), or the named backend is in another workspace (`details.reason: "wrong-workspace"`, `details.heldIn`). Exit 1. |
| `SDK_WORKSPACE_CHANGED` | A `deploy --to workspace` would overwrite objects changed in Xano since the last sync (`details.reason: "workspace-changed"`, `details.objects[]`, `details.changedThere[]`, `details.changedBoth[]`, `details.baseline`); pull first, or `--overwrite` deploys over them. Exit 2. |

## CLI warnings

Printed as `! …` on stderr, and as `{ code, message }` in a `--json` document's `warnings[]`.

| Code | Meaning |
| - | - |
| `agents.refresh-failed` | A managed block (AGENTS.md, the README's Built-with footer) could not be refreshed; the compile itself went on. |
| `agents.symlink` | … is a symlink — left it and its target untouched. |
| `branch.deletion` | … will be permanently deleted and CANNOT be recovered: |
| `branch.inventory-unknown` | The branch inventory could not be read, so what this wipe destroys is UNKNOWN. |
| `branch.live-unverified` | Could not verify whether a branch is live after the replace. |
| `branch.none-live` | No branch is live in workspace #… — "…" becomes the branch the runtime serves. |
| `branch.not-found` | No branch named "…" on … — nothing was deleted. |
| `branch.production-cutover` | This is a production cutover for workspace #…. |
| `branch.settings-withheld` | … workspace setting… will NOT be applied from branch "…": … |
| `branch.shared-schema-changed` | … shared-schema change… applied to the LIVE workspace. |
| `branch.shared-schema-unknown` | The live workspace could not be read, so whether this changed shared schema is UNKNOWN. |
| `branch.stale-schema-refs` | "…"'s logic writes … the shared tables no longer have — once it is live, … nothing there: |
| `branch.unlabeled` | … branch… here carr… no label: |
| `canonical.differs` | … public URL… the value this project compiled: |
| `canonical.invented` | … public URL… will be invented by the instance, and this project will not know …: |
| `credential.env-outranks` | … set in this environment, outranking this credential — commands will keep using …. |
| `credential.env-overrides-pin` | Using the … credential from the environment — ignoring …, which pins this project to profile "…". |
| `credential.readable-file` | … can be read by other users of this machine, and it holds your Xano credentials. |
| `credential.shadowed-global` | Using project-local …, … (…, workspace …), but a global credential for …, workspace … also exists under the same profile name — the local one wins. |
| `credential.unpinned-profile` | The project has no `xano.profile.json` and several profiles are stored, so the run used the default one; `profile use` pins it. |
| `decode.findings` | Not everything round-tripped cleanly — … (listed below). |
| `deploy.destructive` | The landing deletes objects or data on the target; each operation is listed, with the rows a pruned table loses. |
| `deploy.dry-run-refusal` | A real run would refuse: … |
| `deploy.env-written` | Environment variables from the bundle … written. |
| `deploy.ephemeral-write` | Says which ephemeral this deploy writes to. |
| `deploy.import-failed-backup` | The import failed. Your pre-deploy snapshot is on branch "…". |
| `deploy.open-no-url` | --open had no URL to open — the deploy reported none. |
| `deploy.overwrite-changed` | `--overwrite`: … object… changed in Xano since the last sync … overwritten: |
| `deploy.replace-wipe` | `--replace` wipes … before importing — including table data and history. |
| `deploy.rows-written` | Table rows from the bundle … written. |
| `deploy.tenant-write` | This deploy writes to a target that is not an ephemeral, named in the message. |
| `deploy.tests-not-run` | The deploy stands, but its tests could not be run: |
| `dev-env.sync-failed` | The frontend's dev env file could not be pointed at the deployed backend; the deploy itself landed. |
| `doc-token.cleared` | Documentation tokens: the named scopes are sent EMPTY on purpose, clearing that doc site's gate. |
| `doc-token.not-written` | Documentation tokens: … found and NOT written (--no-secrets). |
| `doc-token.orphan` | Documentation tokens: `…` holds … entr… no scope in this source claims — …. |
| `env-pull.declared-missing` | … holds no value for …, which this project declares — so … has none for … either, and a deploy has nothing to send. |
| `env-pull.dropped-keys` | Dropped … key… that … only in the local …: …. |
| `env-pull.invalid-name` | … could not be written: … — a name is letters, digits and `_`, and does not start with a digit. |
| `env-pull.unwritable-value` | … could not be written: the dotenv format carries no newlines or edge whitespace in a value. |
| `ephemeral.duplicate-name` | … also named "…" (…) — this deploy created … beside …. |
| `ephemeral.entry-changed` | … was last deployed from …; …. |
| `ephemeral.expires-not-applied` | --expires-hours … was not applied: … already exists, and an ephemeral's lifetime is set only when it is created (this one expires …). |
| `ephemeral.not-found` | No ephemeral named "…" — nothing was deleted.… |
| `ephemeral.rename-failed` | The deploy landed, but renaming … to "…" failed: …. |
| `export.env-example-cli-skew` | This CLI is another version than the project's installed SDK, so it left `.env.example` for the installed CLI to render. |
| `export.hosted-files-omitted` | Exported bundle names hostedFile() icons whose files it does not carry: …. |
| `filter.unresolvable` | Filter "…" (in …) is not engine-resolvable and will 500 at runtime… |
| `generate.replace` | A regeneration would replace or delete files edited since the last one; each is listed before anything is touched. |
| `gitignore.added-export` | Added … to … — … holds secrets. |
| `gitignore.credential-tracked` | … is tracked by git, so its ignore rule cannot keep the token just written out of the next commit. |
| `gitignore.update-failed` | Could not update.gitignore (…). |
| `init.install-failed` | The new project's dependency install (with its package manager) did not complete; the files are written, and running that install in the project is the whole repair. |
| `init.lock-derive-failed` | xano/index.ts does not load yet, so … and … were not written: … |
| `init.module-config-dropped` | A module's configuration could not be serialized and was left out of package.json. |
| `init.overwrite` | … project file… outside …/ will be overwritten (--force): |
| `init.roundtrip-skipped` | Skipped the round-trip check (--skip-roundtrip) — the tree is unchecked. |
| `init.sdk-skew` | The tree resolved a different @xano/sdk than the CLI that generated it — the likely cause of round-trip mismatches. |
| `init.strict-warnings` | …/ carries … export warning… (printed above) that `npm run xano:check` fails on — it exports with `--strict`. |
| `init.unverified` | The pulled tree was not round-trip checked (its dependencies are not installed); the remedy names the check to run. |
| `init.verify-failed` | Verification FAILED — the objects listed above do not re-export as they were pulled. |
| `init.workflow-exists` | … already exists — moving the new workflow there replaces it. |
| `landing.record-failed` | The prune landed, but … could not be updated: … |
| `local.foreign` | Left running, not started by xanosdk: … |
| `local.import-failed` | The import failed — the engine is still running, so nothing needs restarting: |
| `local.list-failed` | Could not list running engines, so none are shown: … |
| `local.not-pinned` | No package.json in …, and it is not a Xano SDK project, so the Xano Engine was not pinned — this deploy runs the latest engine. |
| `local.pin-unusable` | The project's pinned engine version could not be read and was not used. |
| `local.runtime-kept` | Kept the unpacked runtime (…): … still running on it. |
| `local.stale` | … is running …, but the engine cached here is …. |
| `local.stop-failed` | … was listed as running but did not stop…. |
| `local.version-invalid` | … This deploy runs the latest Xano Engine and the field is left as written — set it to a version like "v0.1.5", or run `xanosdk local update` to pin one. |
| `lock.ceded-canonical` | A lock entry kept its guid but ceded its canonical to a live object; a rename moves the entry so the object keeps its URL. |
| `lock.created-in-ci` | This lock was created in CI, which means the repository does not have one. |
| `lock.dropped-entry` | A stale lock entry was dropped because its identity reappeared under a live name (a reverted or identity-keeping rename). |
| `lock.duplicate-identity` | xano.lock holds two entries with one identity. |
| `lock.identity-only` | --identity-only — nothing was evaluated, so nothing confirms … orphaned. |
| `lock.import-code-pinned` | … was not adopted: its def pins `guid: "…"` in code, which wins over xano.lock, so the live guid … would be replaced again at the next export. |
| `lock.module-orphans` | …/xano.lock still pins … the workspace no longer exports (the removed module's objects). |
| `lock.no-canonicals` | No canonicals found in … — a configuration-only export strips them, so only guids were adopted. |
| `lock.not-found` | writeBundle found no xano.lock and built unlocked: guids derived from names, so a rename recreates. Pass `lock:`. |
| `lock.orphan` | xano.lock entry "…" matched nothing this export (no workspace canonical emitted). |
| `lock.orphan-adopted` | xano.lock entries `lock import` adopted match no exported object — objects still serving that this project has not ported; a bare `lock prune` keeps them. |
| `lock.prune-adopted` | … adopted by `lock import`. |
| `lock.prune-adopted-kept` | Kept … `lock import` adopted that this code does not declare: …. |
| `lock.prune-near-miss` | "…" is not in …. |
| `lock.rename-unchecked` | Could not evaluate … to check this rename, so nothing confirms "…" was renamed in code. |
| `lock.repinned-table` | A table's def pins a new guid; xano.lock keeps the old one as `replaced`, so a keep-data deploy into an environment still holding it refuses rather than dropping its rows. |
| `lock.repointed` | None of xano.lock's entries appear in …, so this tree now points at a different backend. |
| `lock.root-shadowed` | A xano.lock also sits at the project root, but `xanosdk export` reads … (beside …), so …. |
| `lock.write-failed` | Could not record the source's identities in xano.lock (…). |
| `login.client-reregistered` | The registered client was rejected — re-registering and retrying once. |
| `login.no-refresh-token` | No refresh token was issued (offline\_access not granted); push will require re-login once the access token expires. |
| `login.paste-failed` | The pasted sign-in code or URL could not be read; the link is still valid, so paste again. |
| `logout.env-still-set` | … — commands keep authenticating with …. |
| `logout.pin-signed-out` | … still pins this project to "…", which is signed out now. |
| `logout.revoke-failed` | Did not revoke …: … The token was not sent. |
| `logout.shared-file` | Clearing … in the shared credential file … — this affects every project that reuses it. |
| `logout.unreadable` | Could not read … (…). |
| `merge.symlink` | … is a symlink — left it and its target untouched. |
| `microservice.failed` | Some microservices failed to start: |
| `microservice.starting` | Microservices are still starting (…/… ready) — they should come up shortly: |
| `microservice.status-unreadable` | Could not read microservice status (the backend deployed fine): |
| `module.describe-failed` | … could not describe what it contributes and was skipped. |
| `module.disabled` | … is switched off in this project (`"enabled": false`). |
| `module.gitattributes-conflict` | .gitattributes already carries … contributes, outside any managed block. |
| `module.install-failed` | … failed — the module was not added. |
| `module.kind-unknown` | … does not declare a module kind we recognize, so it is read as an ordinary package. |
| `module.legacy-peer-deps` | Installed with --legacy-peer-deps: …. |
| `module.load-failed` | Could not load …/index.ts to … (…). |
| `module.peer-mismatch` | The project already declares a peer a toolchain module needs, and the installed version falls outside the module's range; it was left as it is. |
| `module.peer-not-added` | A peer a toolchain module needs could not be added as a direct dependency; the line names the command that adds it. |
| `module.peer-unresolved` | … declares a peer range this project does not satisfy; --legacy-peer-deps did not resolve it either. |
| `module.removed-from-marketplace` | … has been removed from the marketplace. |
| `module.sdk-skew` | … requires `@xano/sdk` … — the module was not added. |
| `module.setting-dropped` | …: `…` is no longer asked, so its stored setting was dropped. |
| `module.settings-unreadable` | … could not read its stored settings back; its defaults were used instead. |
| `module.stale-settings` | … is no longer a dependency, but this project still records settings for it. |
| `module.unconfigured` | … was left unconfigured, so it runs on its own defaults. |
| `module.uninstall-failed` | … could not be removed again — it is still in this project's dependencies. |
| `module.unregistered` | … is installed but not registered — …. |
| `operation.outcome-unknown` | Outcome unknown — check with `…` before retrying. |
| `plan.canonical-change` | The merge … move … — the project pins another `canonical`, and every endpoint under the old slug stops answering: |
| `plan.column-drop` | The landing drops columns the target has, and their values with them. |
| `plan.column-retype` | A kept column changes type; stored values stay, and one that does not read as the new type reads null. |
| `plan.doc-not-updated` | The workspace … NOT be updated — a merge does not write the workspace's `documentation` block. |
| `plan.enum-values-removed` | An enum column loses values; a row holding a removed value reads null until it is restored. |
| `plan.env-drop` | … environment variable… will be DROPPED: … |
| `plan.env-kept` | … live value — the project's differs, and a merge does not update values: …. |
| `plan.index-change` | The landing adds or drops indexes; a unique index is refused over duplicate rows. |
| `plan.not-null-kept` | A column becomes nullable, but the merge keeps NOT NULL on the table. |
| `plan.not-null-tightened` | A column stops being nullable; rows holding null read back as the type's empty value. |
| `plan.nothing-matched` | NOTHING MATCHED. … be created and … already in this … deleted — not one of them shares an identity with this project. |
| `plan.object-remove` | The replace DELETES … — a replace clears everything … holds: |
| `plan.object-remove-unlisted` | Could not read … to list what the replace clears that this project did not land; `--yes` deletes it unlisted. |
| `plan.realtime-history-detached` | The merge … detach realtime history: sockets on the old … stop connecting, and the `conversation` transcript and the `at_least_once` replay stay under the ol… |
| `plan.schema-additive` | The new tables and columns the landing adds. |
| `plan.seed-not-written` | … seed rows a merge does not write — …. |
| `plan.server-note` | A note the instance attached to the landing plan, passed on as it came. |
| `plan.table-drop` | The merge … DROP … the project no longer declares, …: |
| `plan.table-rename` | The landing renames tables matched by identity, keeping their rows. |
| `plan.tableref-retarget` | A table reference points at another table; the ids the rows hold now name that table's rows. |
| `plan.target-unreadable` | Could not read the target …, so this plan does not account for dropped columns or env that will not update. |
| `plan.workspace-rename` | This workspace will be RENAMED: "…" → "…" |
| `preflight.check-unavailable` | A toolchain module's check could not run: the engine comparison was unavailable. |
| `preflight.import-rejected` | Import rejected by the engine: |
| `preflight.nothing-captured` | nothing to capture (no objects round-tripped) |
| `preflight.roundtrip` | round-trip ? … — not found in the imported workspace |
| `preflight.runtime` | A preflight request ran and the engine threw; the status alone would read as a pass. |
| `preflight.teardown-failed` | Could not delete the validation environment; it will expire on its own: |
| `profile.local-shadows-pin` | This project pins profile "…" (…), which is in … but not in …. |
| `profile.missing` | … is selected here but not stored in …, so no profile is active — commands here fail until it is added or another is selected. |
| `profile.not-found` | No credential profile "…" in … — nothing to delete. |
| `profile.orphan-ephemeral` | The environment "…" was deployed under "…", and no stored profile reaches it now. |
| `profile.pin-deleted` | … still pins this project to "…", which no longer exists. |
| `profile.pin-missing` | … pins profile "…", which this machine does not have — commands here will fail until you run …, or re-pin with `…xanosdk profile use <name>`. |
| `profile.project-pin-wins` | This project pins its own profile in …, which still wins here. |
| `promote.canonical-not-served` | Public URL slug… pinned in code … served under another value — every route a frontend builds from … answers 404 there: |
| `promote.canonical-substituted` | Public URL slug… the release declares … served under another value (not pinned in code, so the instance chose): |
| `promote.identities-unchecked` | Whether this release's names and pinned public URL slugs are free in your workspace was not checked — …. |
| `promote.missing-objects` | … declared object… did not arrive: |
| `promote.no-landing-record` | No landing will be recorded: this directory is no project, so no xano.lock records what lands (a later `--prune` deletes only what a lock records). |
| `promote.seed-rows` | "…" carries rows for … table… (…), and they are not written: a promote lands logic on a branch, and tables are shared by every branch. |
| `promote.server-release` | `promote` lands a release the server holds, so the local pre-flight did not run; what it checked instead is listed. |
| `promote.suffixed-rename` | … look… like a suffixed rename of a declared name — check it is the object you meant. |
| `promote.unverified` | Contents NOT verified — the release landed, but verification could not run (…) — check what landed with `xanosdk workspace export --branch … --path -…` |
| `publish.unbuilt-source` | The directory being published looks like frontend source, not a build output. |
| `pull.env-check-failed` | Could not check …/… for missing values (…). |
| `pull.kept-duplicates` | … kept file… objects the decoded tree declares too. |
| `pull.kept-files` | Kept … file… in …/ no decode wrote — … yours, and not part of the decoded tree: |
| `pull.lock-dropped` | …/xano.lock entr… no counterpart in … and will be dropped: |
| `pull.lock-repinned` | …/xano.lock entr… will be re-pinned to the object … holds under the same name: |
| `pull.module-replaced` | … registers … (`…`), and the decoded entry registers plain copies of the objects it contributed instead — a later … upgrade no longer reaches them. |
| `pull.no-git` | Not a git repository — nothing here holds the version of …/ about to be replaced. |
| `pull.replace` | A pull replaces files under `xano/` (edited since the last pull, or no longer generated); each is listed. |
| `pull.seeds-dropped` | … table… seeded in code, and the pulled tree drops … `seed:`: |
| `pull.settings-lost` | … carries no workspace settings, so the workspaceConfig in …/… is rewritten without its …. |
| `pull.tsx-needed` | …/ is now … TypeScript files, and an entry that imports its own modules loads only under tsx, which this project does not have — the next deploy fails until… |
| `pull.unverified` | Could not check that …/ round-trips — loading its TypeScript entry needs `tsx`, which is not installed. |
| `release.already-gone` | Release "…" was already gone. |
| `release.contents-missing` | Its stored contents are missing — cut it again from a live environment. |
| `release.copy-unrecorded` | Transferred, but recording on "…" which release it was copied from failed (…). |
| `release.delete-in-use` | Release "…" is in use: …. |
| `release.drift` | … does not match … (… object… differing, missing or extra). |
| `release.env-created` | … env var… in "…" … NOT set on … and will be CREATED carrying the value the release was cut with: …. |
| `release.env-unset` | Release "…" reads … env var… doesn't set: …. |
| `release.name-stored` | The destination stored it as "…": "…" was taken by the time it landed. |
| `release.no-env` | The release carries no env vars (or no documentation settings), so what it lands on comes up with them unset. |
| `release.not-found` | No release named "…" on … — nothing was deleted. |
| `release.rows-transferred` | This release carries table rows, and they go to the destination with it: |
| `release.seed-rows-not-decoded` | … carries seed rows for …, and a decoded tree carries no rows — they are not in …/. |
| `release.transfer-cancelled` | Transfer cancelled — nothing was imported. |
| `routes.cli-skew` | This CLI is another version than the project's installed SDK, so it left the route table for the installed CLI to render. |
| `routes.module-failed` | A toolchain module could not generate its section of `routes.gen.ts`; the rest was refreshed and its previous block, if any, was kept. |
| `routes.not-written` | The route table (`routes.gen.ts`) was not written this run; the line says why and what writes it. |
| `routes.realtime-unresolved` | …: leaving out … — … — whose canonical URL token resolves nowhere, along with their channels. |
| `secrets.cleartext-export` | … carries … in cleartext — written owner-only (0600); do not commit it. |
| `secrets.cleartext-stdout` | The export carries … in cleartext — written to stdout, where no file permission protects it; do not commit or log it. |
| `secrets.doc-token-written` | Documentation tokens: wrote … to `…` — …. |
| `secrets.env-written` | Workspace env: wrote … from the bundle to `…`. |
| `secrets.local-only` | `…` is SECRET MATERIAL and is gitignored, so a teammate's clone and CI both need `--secrets-file` or `--doc-token` instead. |
| `secrets.not-ignored` | … holds secrets and git was not ignoring it. |
| `secrets.tracked-by-git` | … holds secrets and is tracked by git — an ignore rule cannot untrack it. |
| `secrets.vault-in-bundle` | … contains … private stored …. |
| `seed.guarded-columns` | Could not read which columns are sensitive in … — the source's export does not carry …, so only `internal` and password columns were checked: … |
| `seed.none-declared` | `--seed` was passed, but no table in this project declares seed rows — no rows will be written. |
| `seed.password-hashes` | Seed rows land password columns as given — they must already be hashes. |
| `static-env.not-injected` | The deploy's frontend config was not injected into some static routes (no HTML document or `<head>`); they run with it unset. |
| `static-env.secret-like` | A `--static-env` value looks like a secret, and every one is published in the static site's config. |
| `static-env.unscannable-seed` | … non-public seed column… the static scan cannot search for — too short to match on, or not text at all — so they were NOT checked. |
| `static.hidden-unserved` | The build has files under a dot segment (`.well-known/`, …), which the static host never serves; those paths answer with the fallback page. |
| `static.link-skipped` | A symlink in the build points outside it, or to nothing, so it was not uploaded. |
| `static.republish` | The import failed — republishing the frontend so the static host keeps serving. |
| `static.routing-inferred-multipage` | Routing was inferred as multipage only because the build ships … beside index.html — the shape of a single-page app with its own … page. |
| `static.teardown` | This replace takes the frontend… at … down — a replace clears …'s static hosting, and this one publishes none. |
| `static.teardown-unknown` | Could not read …'s static hosting, so this cannot say whether a frontend serves there — this replace takes down any that does. |
| `static.unconfirmed-live` | Could not confirm the frontend is live within the wait window — the build uploaded and should come online shortly. |
| `static.upload-failed` | The static-host upload failed — the backend deploy stands: |
| `sync.record-failed` | The … succeeded, but its sync baseline could not be recorded in …: … |
| `tenant.deploy-partial` | The deploy stopped partway: … release "…" declares… — answered as a NOT NULL violation, though the release makes no field required: the value converts to nul… |
| `tenant.deploy-unconfirmed` | Compare its `deployedAt` and `deployedReleaseId` with what they were before this deploy (deployedAt …, deployedReleaseId …). |
| `tenant.identities-unchecked` | Whether this release's names and pinned public URL slugs are free on … was not checked — …. |
| `tenant.not-found` | No tenant or ephemeral named "…" — nothing was deleted…. |
| `tenant.seed-replaces-rows` | "…" was cut with rows, and a tenant deploy REPLACES … rows on … with the release's — every row there now is deleted: |
| `tenant.server-release` | `tenant deploy` lands a release the server holds, so the local pre-flight did not run; what it checked instead is listed. |
| `test.list-truncated` | Stopped after … tests — the list did not terminate, so some may not have run. |
| `toolchain.failed` | A toolchain plugin's hook failed and was skipped; its check did not run. |
| `toolchain.load-failed` | … could not be loaded and … skipped. |
| `update.available` | A new @xano/sdk is available: … → … |
| `upgrade.partial` | Could not restore the … range in package.json: … |
| `workspace-env.compared-empty` | Workspace env: … compared as EMPTY (--allow-empty-env). |
| `workspace-env.missing-values` | … declared env var… no value in …: …. |
| `workspace-env.not-written` | Workspace env: the bundle carries … (…) — NOT written (--no-secrets). |
| `workspace-env.undeclared` | A workspace env var is supplied but not declared in `workspaceConfig({ env })`; the deploy would add it. |
| `workspace-env.unsupplied` | A declared workspace env var has no value from any source this run reads. |
| `workspace-env.valueless` | … env var… declared with no value in the bundle (…) — see …/.env.example. |
| `workspace.drift` | … does not match this project’s compile (… compared, … differing, … missing, … unexpected). |
| `workspace.unreachable` | The credential is pinned to a workspace id its own workspace list does not hold; the ids it can reach are listed. |

## Build diagnostics

Raised while a workspace compiles (`export`, `deploy`, `release`, …). A warning fails `--strict`; a def accepts one with `diagnostics: { allow: ["<code>"] }`.

| Code | Meaning |
| - | - |
| `agent.args-placeholder-unpassed` | …: `s.ai.agent.run` of agent "…" passes args …, but the agent's prompt reads `{{ $args… }}`, which this run never passes, so it resolves to nothing. |
| `agent.literal-api-key` | agent "…" spells its `llm.apiKey` literally. |
| `api-group.cors-no-methods` | apiGroup "…": `cors.mode: "custom"` enables no `allowMethods`, so no `access-control-allow-methods` is sent and a preflight has nothing to approve. |
| `api-group.cors-no-origins` | apiGroup "…": `cors.mode: "custom"` with an empty `allowOrigins` matches no request, so responses carry NO `access-control-*` headers and every browser call… |
| `api-group.cors-origin-unmatchable` | A stored CORS origin no browser `Origin` can equal (path, trailing slash, no scheme, uppercase, wildcard), kept on a pulled group. |
| `api-group.cors-wildcard-origin` | apiGroup "…": `allowOrigins` contains `"*"`, which is compared as a LITERAL origin under `mode: "custom"` — no browser sends `Origin: *`, so it matches nothi… |
| `api-group.docs-gate-unresolved` | … API group… declare… a documentation gate (`require_token: true`), but no token was supplied for it — …. |
| `api-group.docs-public` | after this deploy, … API group… documentation will be PUBLICLY READABLE — …. |
| `bundle.function-value` | A def holds a JavaScript function where a JSON value belongs; nothing can serialize it. |
| `bundle.non-json-value` | A def holds a value JSON cannot carry (`undefined`, a class instance, a `Date`, `NaN`, …). |
| `cache.ttl-not-positive` | … "…": `cache.ttl` is … — the engine stores a response only for a ttl of 1 or more whole seconds, so this cache never holds anything while every call still l… |
| `condition.mixed` | … "…": a condition mixes AND and OR at one level (`mixed(...)`). |
| `db.addon-duplicate-alias` | …: two attached addons graft as "…" — the later overwrites the earlier on every row. |
| `db.addon-unknown-column` | …: the attached … binds `out("…")`, but the rows it reads have no `…` column — the binding is null on every row, so the addon grafts nothing. |
| `db.addon-unknown-input` | …: the attached … is passed `…`, which that addon does not declare — the engine drops it, so the addon runs with its input unset and grafts nothing. |
| `db.bulk-update-partial-item` | …: `s.db.bulk.update` on table "…" is a full-row REPLACE, and these items omit … — each omitted column is written to its zero value ("" / 0 / null), not left… |
| `db.filter-operand-invalid` | …: a `where` clause fails every request that reaches it, whatever the data — …. |
| `db.internal-column-read` | …: reads `ref("…")`, but "…" on table "…" is `access: "internal"` and a `db.get` does not return it — the row has no "…" key, so this fails at runtime with \`… |
| `db.null-match-arg` | …: `c.null()` is the … of `…`. |
| `db.output-unknown-column` | …: `output` selects "…", but the row has no "…" — the key is absent from the result. |
| `db.query-envelope-read-unpaged` | … "…": `ref("…")` reads the paging envelope, but `s.db.query` "…" is not paged with one, so it binds the row list and `…` is no key of it. |
| `db.query-output-joined-column` | …: `output` selects "…", a JOINED column — a join adds no key to the row, so it is dropped from the result with no error. |
| `db.query-output-mixed-roots` | …: `s.db.query` is PAGED, so `output` selects from the envelope (…) — but …, which no envelope key matches, so … dropped from the result. |
| `db.query-output-not-envelope-rooted` | …: `s.db.query` is PAGED with an envelope (`metadata: true`, the default), so `output` selects from that envelope — but this selection is rooted at the row (…). |
| `db.query-output-totals-off` | …: `output` keeps …, but the envelope carries … only when counting is on — the key is absent from the result. |
| `db.query-output-unknown-column` | …: `output` selects "…", but the row has no "…" — the key is absent from the result. |
| `db.safe-ref-match-arg` | …: a `ref(…, { safe: true })` is the … of `…`. |
| `diagnostics.allow-unused` | … "…": `diagnostics.allow` accepts …, but this export raised no such warning about … — the shape … accepted is gone, or the check no longer finds it. |
| `doc-token.unsupplied` | API group "…" declares a documentation gate and no token was found for it in `…`, so this artifact carries no `documentation` block — the bytes an export wou… |
| `documentation.literal-token` | … spells a documentation token literally in …. |
| `expression.ignore-empty-static-empty` | …: comparison …`…` sets `ignoreEmpty` on an operand that is EMPTY in the bundle. |
| `field.default-not-text` | The `default` at … was stored as … — a field's default is TEXT (a string, number or boolean), and an object, Map, Set or class instance passed there through… |
| `field.email-default-invalid` | The `default` at … is …, which is not an email address — every insert or request that leaves the field out is refused "Invalid email format.". |
| `field.enum-default-not-a-value` | The `default` at … is …, which is not one of the enum's values (…) — a value no request can send back. |
| `field.input-default-invalid` | The `default` at … is …, which … — every request that leaves the input out is refused. |
| `field.input-required-default-ignored` | The `default` at …, input "…" is …, but the input is `required: true` — the engine refuses a request that leaves a required input out ("Missing param") befor… |
| `field.vector-not-nullable` | table "…", column "…" is a vector with `nullable: false` and no default — an empty default becomes NULL only on a nullable column, and `''` is not a vector,… |
| `function.reserved-input-name` | function "…": the input name `…` is reserved by the engine — a call passes its arguments keyed by input name, and the engine skips a `…` key when it evaluate… |
| `guard.role-unsatisfiable` | A guard.role on a table passed by name checks a column the table lacks, or a role its enum column cannot hold. |
| `knowledge.agents-md-mode` | …: `mode: "…"` has no effect on an `agents.md` item — its body is injected in full on every turn regardless. |
| `knowledge.empty-body` | …: the markdown body is empty. |
| `knowledge.multiple-agents-md` | A workspace can have at most one `type: "agents.md"` knowledge item, and this one declares …: …. |
| `knowledge.name-charset` | …: name contains …. The platform accepts the deploy and then silently DROPS the item — the agent ends up with no such knowledge and nothing reports an error.… |
| `knowledge.name-too-long` | …: name is … characters; the platform accepts at most …. |
| `knowledge.newline` | …: `…` contains a newline. |
| `knowledge.refs-include-source` | knowledge "…": … contains …, which … as … — everything under the directory is collected. |
| `knowledge.refs-symlink-skipped` | knowledge "…": … contains …, …, which … not ship — a link is not followed. |
| `lock.same-name-siblings` | … objects share the identity "…" while carrying different guids…. |
| `mcp.elicit-duplicate-key` | …: … more than one `s.mcp.elicit` that can run in one call. |
| `mcp.elicit-outside-mcp` | …: `s.mcp.elicit` runs in a … stack, which no MCP client calls, so there is nobody to ask and it answers `{ action: "cancel" }` every time. |
| `mcp.oauth-claim-unacked` | …: `oauth.claim` "…" can be edited by users at many identity providers, which would let a user choose the row they sign in as. |
| `mcp.oauth-external-incomplete` | …: `oauth` is external mode with no …. |
| `mcp.oauth-hosted-incomplete` | …: `oauth` is hosted mode with no `loginUrl`. |
| `mcp.oauth-preset-client-ids` | …: `oauth.preset` "…" issues access tokens without an audience, so nothing ties a token to this server. |
| `mcp.oauth-revoke-target` | …: `s.mcp.oauth.revoke` needs exactly one of `user_id`, `grant_id` or `all`, but it names … — the platform refuses any other combination every time the state… |
| `mcp.prompt-no-response` | … has no `response` and no top-level `s.return`, so every `prompts/get` of it fails: a prompt's messages are its answer. |
| `mcp.resource-uri-duplicate` | mcpServer "…": resources "…" and "…" share the uri "…". |
| `mcp.write-before-elicit` | …: … runs before `s.mcp.elicit`…. |
| `microservice.early-surface` | this workspace declares … — an EARLY platform surface whose stored shape is expected to change. |
| `microservice.secret-in-bundle` | microservice "…" writes … into this bundle verbatim — the engine stores the value as given, so a `process.env` read here resolves at export, not on the tenant. |
| `microservice.unsupported-block` | microservice "…" declares …, which the engine refuses on import — the workspace fatals mid-deploy, after provisioning has begun. |
| `middleware.auth-null-host` | middleware "…" references auth() and is attached to … "…"…, where …. |
| `middleware.envelope-unnested` | middleware "…" reads … straight off `s.util.get_all_input`, which binds a `{ type, vars }` envelope — the request is under `vars`, so …. |
| `middleware.inp-unresolvable` | middleware "…" reads …, which cannot resolve — an attached middleware has no bound inputs, so this fails at runtime with `Unable to locate input: …`.… Use \`s… |
| `middleware.input-never-bound` | middleware "…" declares `input`, which the host request never binds — `inp()` inside a middleware fails at runtime with `Unable to locate input`, and a decla… |
| `middleware.post-merge-list` | query "…" answers a list, and the post middleware … merges its response into it: the list arrives as an object keyed by index (`{"0":{…},"1":{…},…}`), not th… |
| `middleware.post-reads-request` | middleware "…" is in the post chain of … "…"… and reads … from `s.util.get_all_input`. |
| `query.auth-table-unflagged` | query "…" requires auth against table "…", which is not marked `table({ auth: true })`. |
| `query.auth-table-unregistered` | query "…": `auth` is a table def that isn't registered on this workspace — add it with `registerTables([…])`. |
| `query.input-name-mangled` | query "…" (…) has an input named …, which a query string cannot deliver — the request parser rewrites param names, so `?…=…` … and the input stays empty. |
| `query.path-segment-candidate` | query "…" (…) looks up one row by the `…` input, but the path declares no `{…}` segment — so the value arrives as `?…=…` instead of addressing the resource. |
| `query.route-shadowed` | Two queries in one api group and verb that one request path can match; the route created first answers for both. |
| `realtime.conversation-no-limit` | realtimeChannel "…" sets `conversation: { enabled: true }` with no `limit` — `limit` defaults to 0 and 0 means retain NONE, so nothing is recorded or replayed. |
| `realtime.deliver-explicit` | realtimeMessage "…" sets `deliverTo: "explicit"`, which delivers to NOBODY — nothing selects recipients from inside a handler, and `s.realtime.publish` is no… |
| `realtime.deliver-falsy-return` | realtimeChannelTrigger "…" gates `deliver` and returns `…` — only an explicit NULL drops a message; `false`, `0` and `""` DELIVER IT UNCHANGED. |
| `realtime.deliver-without-per-recipient` | … "…" gates `deliver` on channel "…", but that channel does not set `delivery: { perRecipient: true }` — the engine runs the per-recipient path only when BOT… |
| `realtime.gate-denies-everyone` | … "…" gates `…` but declares no `response`, so it returns nothing on every run — and an empty return is a DENY, which refuses every client. |
| `realtime.join-deliver-object-response` | … "…" serves both `join` and `deliver` with one object response — `join` reads it as the admit decision, but `deliver` reads an object as the recipient's NEW… |
| `realtime.per-recipient-without-deliver` | realtimeChannel "…" sets `delivery: { perRecipient: true }` but no active `deliver` trigger is bound to it, so the flag is a no-op — the engine falls back to… |
| `realtime.publish-unknown-channel` | …: `s.realtime.publish` targets channel path "…" on realtime server "…", but that path is a channel of … only, so no client of "…" can be subscribed to it —… |
| `realtime.publish-unknown-server` | …: `s.realtime.publish` targets realtime server "…", which this workspace does not register. |
| `realtime.server-disabled` | realtimeServer "…" is not enabled — `enabled` defaults to FALSE, unlike every other `enabled` — but … channel… registered on it, so no client can connect to …. |
| `redis.ratelimit-no-error` | … "…": an `s.redis.ratelimit` has no `error`, so it never stops a request — over `max` it …. |
| `reference.unresolved` | … references …, which is not registered on this workspace. |
| `response.unbound-return` | … "…" ends with s.return(...) but has no `response` field. |
| `search.request-only-filter` | … pipes a search operand through `…`, which evaluates only in the request. |
| `seed.invalid` | A seed row does not match its table's columns. |
| `seed.public-seed` | Table "…" declares publicSeed but has no `seed`: there are no seed values to declare public. |
| `stack.agent-tools-off` | …: `s.ai.agent.run` of agent "…" leaves `allowToolExecution` unset, so the agent runs with its tools off: it sees them but never calls one, and answers as if… |
| `stack.auth-no-caller` | … "…" reads `auth()`, but …: it deploys clean and never holds the caller's identity. |
| `stack.auth-null-host` | … "…": an `s.redis.ratelimit` in its stack keys off auth(), where …. |
| `stack.blank-table` | … has … (…) bound to no table (`table: null`) — … nothing when run. |
| `stack.col-outside-query` | `col("…")` outside a `db.*` statement's where/sort/eval — the engine reads it as the column NAME, so a condition on it is decided by that text and a response returns it. |
| `stack.env-undeclared` | … "…" reads …, which … among the … environment variable… this workspace config declares (…). |
| `stack.expect-outside-test` | … runs … in its stack. |
| `stack.inp-undeclared` | … "…" reads …, which … here — ….… This deploys clean and fails at runtime with `Unable to locate input: …`. |
| `stack.loop-control-outside-loop` | … runs `…` outside any loop. |
| `stack.password-input-double-hash` | …: `s.security.check_password` reads `inp("…")`, and the input `…` is declared `input.password()`. |
| `stack.reserved-var-namespace` | `ref("…")` reads a stack variable named after a reserved namespace (`auth`, `input`, `env`, …) that nothing binds — use its accessor (`auth()`, `inp()`, `env()`, …) — a 500 at runtime. |
| `stack.to-throw-isolated-var` | …: `ref("…")` inside an `s.expect.to_throw` body names `…`, which is bound OUTSIDE the body. |
| `stack.unbound-var` | `ref("…")` reads a variable nothing in the stack binds with `as` — `Missing var entry`, a 500 at runtime. |
| `stack.zip-password-absent` | …: `…` sends no … key (`…: null`), and the engine rejects that at run time with `Missing param: …`. |
| `statement.decode-only` | A pulled workspace carries a statement Xano SDK has no factory for, as a `raw(…)` call; replace it with the statement it stands in for. |
| `statement.omitted-input` | …: `s.function.run` of function "…" does not pass …. |
| `statement.reserved-input-name` | …: `…` passes an input named `…`, which is reserved by the engine — it skips a `…` key when it evaluates a call's arguments, so the callee receives the uneva… |
| `statement.run-family-host` | … contains `…`, which only runs inside a workflow test. |
| `statement.unknown-input` | …: `…` of … "…" passes `…`, which that … does not declare — the engine drops it, so the target never sees the value. |
| `storage.stored-file-input` | … "…": `s.storage.…` reads `inp("…")`…, an `input.…()` — that input takes an already-stored file, so an upload to it is refused (`400 Missing param: path`) b… |
| `switch.missing-break` | … has a `s.switch` whose case … omits `break: true`, so a match there FALLS THROUGH and also runs …. |
| `table.column-default-unfit` | A JSON-storage column's `default` its type cannot hold: the table deploys, then every insert that leaves the column unset is refused. |
| `table.column-name-unusable` | A stored column name the rule refuses (inserts, filters or reads fail on it), kept on a pulled table. |
| `table.reserved-column-name` | table "…": the column name `…` is reserved by the engine — it is the key a block statement stores its sub-stack under, and an insert's parameter map collides… |
| `table.view-duplicate` | …: `id` "…" is also the id of … — each view needs its own uuid. |
| `table.view-id-not-uuid` | …: `id` "…" is not a uuid, and the engine keys the view by it. |
| `table.view-unknown-column` | …: `…` names "…", which is not a column of this table… The view exports and then …. |
| `test.live-datasource` | A def's test runs against the "live" datasource, which every run clones first; `datasource: ""` or a small fixture is the default. |
| `test.unknown-input` | …: `input` passes `…`, which the … does not declare — the engine drops it, so the test runs without it. |
| `tool.output-mismatch` | tool "…": its `response` …. |
| `toolset.primitive-reads-auth-ungated` | mcpServer "…": … "…" reads `auth()`, but its entry names no auth table, so it runs with no caller and every `…` answers `-32603 "Access Denied"`. |
| `toolset.tool-reads-auth-ungated` | … "…": tool "…" reads `auth()`, but its entry names no auth table, so the tool runs with no caller. |
| `toolset.tool-ref-zero` | … `tools[…]` is `id: 0`, which references no tool — engine ids start at 1. |
| `trigger.no-action` | … "…" enables no action, so it deploys and never fires. |
| `trigger.search-bare-column` | tableTrigger "…": `search` reads `col("…")`, which names neither row the condition is tested against. |
| `trigger.search-unknown-column` | tableTrigger "…": `search` reads `col("…")`, but its table has no column "…" — it declares …. |
| `trigger.unbound` | … "…" names no object to fire on, so it deploys bound to nothing and never runs. |
| `value.int-out-of-range` | … "…" stores the integer …, outside the signed 64-bit range (… to …). |
| `value.interpolated-object` | … stores … — `[object Object]` is the JS toString of a tagged value (`ref()`/`inp()`/`c.*`) interpolated into a template literal or `+` concatenation, which… |
| `value.obj-zero-based-numeric-keys` | … stores the object …, whose zero-based numeric keys make the engine evaluate it as a LIST, not an object. |
| `value.regex-operands-reversed` | … pipes a regex filter's SUBJECT and passes its PATTERN as the argument: …. |
| `value.timezone-unknown` | … "…": … names a timezone the engine does not apply — it formats in UTC instead, without an error. |
| `workflow-test.live-datasource` | A workflow test runs against the "live" datasource, which every run clones first; `datasource: ""` or a small fixture is the default. |

***

*Generated from @xano/sdk 1.0.9.*


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.