Error codes

Every stable error code the API can return, and what each one means.

When a request fails, the response body carries a stable machine-readable code alongside the human-readable message:

{
  "error": {
    "error": "App database is not provisioned yet",
    "code": "APP_NOT_PROVISIONED",
    "details": { "appUid": "..." }
  }
}

Branch on error.code, never on error.error. The code is the contract and will not change; the message is prose and may be reworded at any time. details carries whatever context is useful for that specific failure.

The Status column is the HTTP status the code is actually thrown with, verified against the real throw sites by a test in the backend suite rather than maintained by hand.

Not every failure carries a code. A generic policy denial returns 403 with code: null, so treat error.code as present-or-absent rather than assuming one is always there.

There are 378 codes.

App lifecycle

CodeStatusMeaning
APP_NOT_PROVISIONED409The target app has no provisioned database yet. Provision the app before calling its API.
APP_NOT_FOUND404No such app within your organization. Returned identically for an app that does not exist and one owned by another organization.
ROUTE_NOT_FOUND404No route answers this method and path. Check the URL, the method, and the app uid.

AutoCRUD write failures

CodeStatusMeaning
CREATE_REQUIRED_FIELD_MISSING400A column the table requires was absent from the request body.
CREATE_DUPLICATE409The row violates a unique constraint on the table.

The row edge (helpers/rowEdge.js)

CodeStatusMeaning
ROW_FIELD_NOT_ACCEPTED400A field the data API does not take: a row's internal id, its uid (minted by the platform), a scope or actor column, or a raw foreign-key column. The message names the field to use instead.
ROW_NOT_FOUND404No row with that uid that you can reach: it does not exist, was deleted, or belongs to another organization (the same answer for all three). In a batch, details.index names it.
ROW_REFERENCE_NOT_FOUND400A <column>_uid reference names no row in the table it points at. The message names the column.
ROW_EDGE_COLLISION409The table cannot be served: a foreign-key column's uid name (<column>_uid) is also the name of a real column. Rename one of them.
ROW_ORG_REQUIRED400The table's rows belong to an organization: name the app organization a new row belongs to (orgUid in the console and agent tools, the row's org_uid in a handler acting for the app's owner). An app with no organizations yet cannot take rows in such a table.
ROW_ORG_NOT_FOUND400orgUid (or a row's org_uid) names no organization in the target app that the caller reaches.
PAGE_CURSOR_INVALID400A page read with after was given a cursor this API did not issue for that table (changed, from another table, or sealed under a retired secret), or a sort or offset, which keyset paging does not take.
QUERY_INVALID400A list query this API cannot run: malformed JSON in where, an unknown operator, a column the table does not serve, or a sort direction other than asc or desc.
QUERY_TOO_COMPLEX400A list query past the bounds one request may ask for: too many conditions, nested too deep, too many $in values, too many sort columns, or a where that is too long. details.limits names them.
BATCH_TOO_LARGE400A batch write carries more rows than one request may (details.maxRows). Split it.
QUERY_TIMEOUT422A list query ran longer than one request may. Narrow it, or add an index on the columns it filters or sorts by.
PAGE_CURSOR_UNAVAILABLE500The server has no secret to seal page cursors with (ACCESS_TOKEN_SECRET is not set).
AGENT_ORG_UNRESOLVED403The agent belongs to no organization of the app it is acting on, and is not the app owner's.
APP_ORG_UNBOUND500Platform code tried to reach an app's data without saying which app organization it acts in.
ORG_REACH_OWNER_ONLY403Only the app's owner, in the console, can change what its agents, jobs and keys may reach.
ORG_REACH_NOT_APPLICABLE409This agent, job or key belongs to one of the app's organizations and acts only there; org reach is for the owner's own.
STORAGE_SHARED_READ_ONLY403This was shared with you by the app's owner: you can open and download it, and add your own files beside it, but not change it or add folders inside it.
STORAGE_SHARING_OWNER_ONLY403Only the app's owner decides what its folders and files are shared with.
STORAGE_SHARING_NOT_APPLICABLE409This belongs to one of the app's organizations; sharing is for the owner's own folders and files.
STORAGE_OUT_OF_REACH403That reaches organizations outside the caller's org reach.

Handler resolution (helpers/handlerResolver.js)

CodeStatusMeaning
HANDLER_NOT_FOUND404No live handler in this app has that name.
HANDLER_NAME_AMBIGUOUS409More than one live handler in this app has that name, so none of them runs. Rename or archive one.
HANDLER_KIND_BOUND409An endpoint still runs this handler: unassign it from its endpoint actions before marking it job-only.
HANDLER_TRIGGER_REQUIRED500Platform code dispatched a handler without saying why it runs it. A defect, never a caller's mistake.
HANDLER_PLATFORM_ONLY403This handler runs only for the platform: its scheduled jobs, or the app owner testing it in the console.

Table protection

CodeStatusMeaning
TABLE_LOCKED423The table is locked against this operation by its protection settings.
COLUMN_REDACTED400That column is redacted, so it cannot be filtered or sorted on.

Review, then confirm

CodeStatusMeaning
REVIEW_HASH_MISMATCH409What you confirmed is not what was reviewed. Review again, then confirm.
PLAN_HASH_MISMATCH409The table changed since this plan was made. Plan again, then apply the new plan.
POLICY_IS_SYSTEM423That policy is seeded platform wiring and cannot be unbound or edited. Bind or unbind your own policy instead.

Custom handlers / execution

CodeStatusMeaning
HANDLER_NOT_IMPLEMENTED501The action is registered on the endpoint but has no handler implementation published.
HANDLER_WORKER_UNAVAILABLE503The isolated handler runtime could not be reached. Transient — retry.
HANDLER_WORKER_BUSY503The isolated handler runtime is at capacity (overall, or for this app). Transient — retry.

Definition as code (notes/app-definition-as-code-plan.md)

CodeStatusMeaning
DEFINITION_CODE_MANAGED409The object is managed by the app's connected repository. Change it there and let the deployment apply it, or have the owner turn on break-glass editing for an incident.
DEFINITION_BUNDLE_INVALID422The definition bundle could not be read: a missing or invalid authoric.json, an unknown folder or key, or a file that fails a check. The message names the file and the fix.
DEFINITION_PLAN_INVALID422The bundle is valid but cannot be applied to this app as it is: something it removes or changes is still used. The message says what to change first.
DEFINITION_SOURCE_UNAVAILABLE409The deployment's source could not be read: the app has no connected repository, the connection was removed, or an uploaded bundle is no longer held.
DEFINITION_OWNER_ONLY403Connecting a repository, the deployment safety settings, break-glass and deploy keys are changed only from the app owner's own console session, never with a key or token.
APP_TYPES_OWNER_ONLY403An app's types are read from the owner's own console session, or with a deploy key for the app.
DEFINITION_REPO_LINKED409The app is already connected to a repository. An app deploys from one; disconnect it first, or change its branch or bundle path.
DEPLOYMENT_SELF_APPROVAL403You caused this deployment, so someone else has to approve it. An owner can turn off Prevent self-approval for a one-person team.
DEPLOYMENT_NOT_WAITING409The deployment is not in a state that allows this: it is no longer waiting for approval, or has already started applying.
DEPLOYMENT_PLAN_CHANGED409What the deployment would apply changed after it was planned, so it was stopped. Deploy again to plan it afresh.
DEPLOYMENT_NOT_ROLLBACKABLE409That deployment cannot be rolled back to: it never went live, or it did not record the versions it ran.

Billing / plan changes

CodeStatusMeaning
PLAN_CHANGE_BLOCKED409The target plan does not fit the organization's current usage. Raised in EITHER direction: a plan's rank decides how it is billed, not which way each individual limit moved, so an upgrade that tightens one limit is refused too. details.blockers lists every resource that is over, with the usage and the target limit, so the customer can free them all at once instead of being refused repeatedly.
PLAN_CHANGE_ALREADY_SCHEDULED409A plan change is already scheduled for the end of the current period. Cancel it before scheduling another — a second would orphan the first schedule in Stripe.
NO_PENDING_PLAN_CHANGE409There is no scheduled plan change to cancel.
PLAN_PAYMENT_FAILED402The card could not be charged for an upgrade, so the plan was NOT changed — the whole change is rolled back rather than granted unpaid. Update the payment method and retry.

Billing / plan limits

CodeStatusMeaning
SUBSCRIPTION_LIMIT_REACHED402The organization's plan limit for this resource is reached. Upgrade the plan or free capacity.
AI_SPEND_CAP_REACHED402An AI spend limit set by this account has been reached. Raise the limit in settings to continue.
FEATURE_NOT_INCLUDED402The organization's plan does not include this feature. Upgrade the plan to enable it.

Account lifecycle locks

CodeStatusMeaning
ACCOUNT_RESTRICTED423The account is read-only because a payment failed. Reads still work; bring the subscription current to write again. details: { state, reason: 'lifecycle', stateReason }
ACCOUNT_PAUSED423The app is paused — for inactivity (restore it from the console) or for non-payment (bring the subscription current). details.stateReason says which. details: { state, reason: 'lifecycle', stateReason }
APP_WAKING503The app was asleep after a period of no traffic and this request started waking it. Retry after the Retry-After interval. details: { retryAfterSeconds, state, stateReason }
APP_RESTORING503The app is being restored from its archive and cannot serve yet. Retry after the Retry-After interval. details: { appUid, retryAfterSeconds }
ACCOUNT_TORN_DOWN423The app's live data was removed after a long pause. It can still be restored from its archive until the archive expires. details: { state, reason: 'lifecycle', stateReason }

Data placement

CodeStatusMeaning
APP_MIGRATING423The app is being moved to different infrastructure and is briefly read-only. Reads continue; writes resume automatically when the move completes.
PLACEMENT_NOT_ENTITLED403The organization's plan does not include the requested data placement tier.
PLACEMENT_PREFLIGHT_FAILED402The app does not fit the requested placement tier — free capacity or choose a larger tier.
PLACEMENT_MIGRATION_IN_PROGRESS409Another placement move is already running for this app. Only one may run at a time.
PLACEMENT_DESTINATION_UNAVAILABLE409The requested placement tier is not available on this deployment yet (for example, S3 is not configured). A queued move resumes once it is.

Platform configuration

CodeStatusMeaning
EMAIL_NOT_CONFIGURED500This deployment has no email sender configured. An operator must configure one.

Email connections and app email (notes/email-connections-and-branding-plan.md)

CodeStatusMeaning
EMAIL_CONNECTION_INVALID400An email connection's server settings are not usable: a mail host, an SMTP submission port, and starttls or tls.
EMAIL_SENDER_INVALID400A sender is not an address (name@example.com) or a domain (@example.com), or the default sender is not one of the connection's senders.
EMAIL_HOST_BLOCKED400The mail host resolves to a private or reserved address, which the platform never dials.
EMAIL_CONNECTION_FAILED502The mail server could not be reached, refused the login, or failed the secure connection. The message says which.
EMAIL_CONNECTION_NOT_FOUND404No email connection or grant by that uid in this org or app.
EMAIL_CONNECTION_UNVERIFIED409The email connection has not passed a test since it was connected or last edited, so it cannot be granted or used.
EMAIL_ALIAS_IN_USE409That alias already names another email connection in this app. Revoke it first to point it elsewhere.
EMAIL_NOT_GRANTED403The app has no email connection by that name (or no default): its owner grants one under App settings.
EMAIL_FROM_NOT_ALLOWED403The from address is not one of the email connection's senders.
EMAIL_PLACEHOLDER_MISSING400A {key} or {{key}} placeholder in the message names no value in its data, so nothing was sent.
EMAIL_MESSAGE_INVALID400The message is missing what every email needs (a recipient, a subject, some content) or has a malformed address.
EMAIL_SEND_FAILED502The app's mail server did not accept the message. It is logged as failed, with the server's reason.

App branding (notes/email-connections-and-branding-plan.md §5)

CodeStatusMeaning
BRANDING_INVALID400A branding field is not usable: a color that is not #rrggbb, a URL that is not https, an address that is not an email address, or text past its length. The message names the field.
BRANDING_ASSET_NOT_FOUND404No file by that uid among the app owner's own files, so it cannot be the logo or icon.
BRANDING_ASSET_NOT_PUBLIC400The file is in a private storage, so an email cannot show it. Move it to a public storage, or make its storage public.
SMS_NOT_CONFIGURED500This deployment has no SMS sender configured. An operator must configure one.
SMS_CHANNEL_UNSUPPORTED501The configured SMS provider cannot send this kind of message. Switch to the Programmable Messaging adapter.
SMS_SUPPRESSED409That number has opted out of messages from this sender and cannot be texted.
ARBITER_NO_LLM409No AI provider is connected for this organization. Connect one in Integrations.
AI_NO_LLM409No AI provider is connected for this organization. Connect one in Integrations.
AI_MODEL_UNAVAILABLE409The configured AI model is no longer available from this provider. Choose a replacement to resume.
LLM_MODEL_NOT_APPROVED400That AI model is not approved for this provider. Choose one from the model list.
AI_TIER_INVALID400sdk.ai takes a tier ("fast" or "default"), not a model. Set the models on your AI connection.

Sign-up doors (api/notes/staff-members-and-authz-hardening-plan.md §2.1)

CodeStatusMeaning
SIGNUP_ORG_NOT_ALLOWED400Sign-up cannot join an existing organization; accept an invitation to join one.
STAFF_SIGNUP_NOT_ALLOWED403Staff accounts are created by setup or by existing staff, never by a public sign-up.

First-run setup (api/notes/staff-members-and-authz-hardening-plan.md §5)

CodeStatusMeaning
STAFF_SETUP_DONE409Setup has already been completed on this install.
STAFF_SETUP_TOKEN_MISSING403This install has no setup token; run npm run staff:setup on the server.
STAFF_SETUP_TOKEN_INVALID403The setup token is not valid.
STAFF_SETUP_INVALID400Setup needs a valid email and a password of at least 8 characters.
STAFF_EMAIL_TAKEN409A staff member with that email already exists.
STAFF_SETUP_REQUIRED409Setup has not run on this install; there is no staff organization yet.
CodeStatusMeaning
INVITE_TOKEN_INVALID400That invitation link is not valid, has expired, or was already used.
INVITE_EMAIL_MISMATCH403This invitation was sent to a different email address.
INVITE_ACCOUNT_TYPE_MISMATCH403This invitation is for a different kind of account.
INVITE_REQUIRED403Staff accounts are created by invitation only.

Platform access (notes/platform-access-plan.md)

CodeStatusMeaning
FEEDBACK_EMPTY400Write something before sending (up to 5,000 characters).
FEEDBACK_NO_SENDER401Sign in to send feedback.
FEEDBACK_NOT_FOUND404That feedback does not exist, or it was removed.
FEEDBACK_STATE400Feedback is new, read or archived.
FEEDBACK_ATTACHMENT_INVALID400Attach up to 3 images (PNG, JPEG or WebP), up to 5 MB each.
NOTIFICATION_TYPE_UNKNOWN400There is no email notification of that type.
NOTIFICATION_TYPE_LOCKED400This email is always sent: it warns before data is deleted.
BOT_CHECK_FAILED403Please complete the bot check and try again.
BOT_CHECK_UNAVAILABLE503The bot check could not be completed. Try again in a moment.
BOT_CHECK_SETTINGS_INVALID400A bot check setting is not usable: a site key or secret key that is not a Turnstile key, or turning the check on without both keys. The message names the field.
BOT_CHECK_SECRET_INVALID400Cloudflare does not recognize that Turnstile secret key. Copy it again from the widget's settings in Cloudflare.
ALLOWED_ORIGIN_INVALID400An allowed domain is not usable: it must be an https origin such as https://yourapp.com or https://*.yourapp.com, with no path. The message names the entry.
ALLOWED_ORIGINS_TOO_MANY400An app can allow up to 25 domains. Use a wildcard such as https://*.yourapp.com for many subdomains.
CORS_ORIGIN_NOT_ALLOWED403This website is not allowed to call this API from a browser. Add its domain to the app's allowed domains.
RATE_LIMITED429Too many requests. Wait the number of seconds in the Retry-After header, then try again.
UPLOAD_NOT_CONFIRMABLE400This upload can only be confirmed by whoever requested it, with the confirmToken its presign returned, before it expires.
IDEMPOTENCY_KEY_REUSED409This Idempotency-Key was already used for a different request. Use a new key for a new request.
IDEMPOTENCY_IN_PROGRESS409A request with this Idempotency-Key is still in progress. Wait for it, then retry with the same key.
REDIRECT_NOT_ALLOWED400redirectTo must be an http(s) address on one of the app's allowed domains, or on localhost.
SIGNUP_INVITE_ONLY403Authoric is invite-only right now. Request access, or use the sign-up link from your invitation.
PLATFORM_ACCESS_REVOKED403Access to Authoric has been revoked for this account.
PLATFORM_ACCESS_LINK_INVALID400That sign-up link is not valid, has expired, or was already used.
PLATFORM_ACCESS_NOT_FOUND404No such access record.
PLATFORM_ACCESS_STATE409That change does not fit this person's current access.

Scheduled jobs: arming (api/notes/staff-members-and-authz-hardening-plan.md §2.4)

CodeStatusMeaning
CRON_ROLE_OUTSIDE_ORG403A scheduled job can only be given a role your organization owns.
CRON_BUSY409The job is running right now. Try again once its current turn has finished.
JOB_ITEM_TIMEOUT504One item of a scheduled job took longer than the per-item limit (60 seconds), and was skipped.

Roster changes from handler code (sdk.roles)

CodeStatusMeaning
PRINCIPAL_NOT_HUMAN403Only people are given roles from handler code.
ROLE_ORG_MISMATCH403A role is granted inside the caller's own organization.
ROLE_NOT_FOUND404That role does not exist.
MEMBER_NOT_FOUND404That member is not in this organization.
USER_NOT_FOUND404That user does not exist.

App creation (api/notes/staff-members-and-authz-hardening-plan.md §2.3)

CodeStatusMeaning
CREATE_APP_ORG_MISMATCH403An app can only be created in your active organization.
CREATE_APP_TENANT_SELECTOR400tenantId / tenantEmail are not accepted; the app is created for your organization's own account.

Policy scope (api/notes/staff-members-and-authz-hardening-plan.md §2.2)

CodeStatusMeaning
POLICY_ROLE_SCOPE_MISMATCH403An organization's policy can only be bound to that organization's own roles; shared roles take only seeded policies.

Staff (api/notes/staff-members-and-authz-hardening-plan.md)

CodeStatusMeaning
ORG_NOT_ADMITTED403This account cannot be a member of that organization.
STAFF_CAPABILITY_NOT_GRANTABLE403Those actions belong to Authoric staff and can only be granted inside the staff organization.
ORG_NOT_BILLED404This organization is not billed; it has no plan or usage to show.
STAFF_ONLY403This action is for Authoric staff only.
PLATFORM_TARGET_STAFF_ONLY403The platform database is not an app target; name one of your organization's apps as targetAppUid.
ACT_AS_INVALID400That act-as request names something we cannot act on.
ACT_AS_REASON_REQUIRED400Say why you need access to this organization; the reason is recorded and shown to the customer.
ACT_AS_NOT_HUMAN403Only a person can act as an organization.
ACT_AS_STAFF_ORG400The staff organization is not something to act as.
ACT_AS_NOT_A_MEMBERSHIP409You are acting as this organization, not a member of it — switch back to stop.
MEMBER_TOKEN_SELF_ONLY403An approver token can only be minted for your own account.
MEMBER_TOKEN_STAFF_ORG403Approver tokens cannot be minted in the staff organization; staff act through sessions.
AI_MODEL_INVALID400The AI model catalog change is invalid; the message says which field and why.
AI_MODEL_NOT_FOUND404No such model in the AI model catalog.
AI_MODEL_EXISTS409That provider and model id are already in the AI model catalog.
AI_MODEL_IN_USE409The model is still in use. It fills a platform role (reassign the role first), or AI connections chose it and the change needs confirming. details lists what points at it.
AI_MODEL_NOT_VERIFIED409Verify the model before approving it: a verification run proves it works through the platform's adapter.
AI_MODEL_UNPRICED409The model has no price, so its spend would not count toward AI spend caps. Add a price, or confirm running it unpriced.
LLM_CONNECTION_NOT_FOUND404No such AI connection in the active organization.
AI_SOURCE_REDACTED400A derived column cannot read from a redacted column. Remove it from the source list or un-redact it.
AI_DERIVED_COLUMN_INVALID400The derived-column configuration is invalid.
AI_EMBEDDINGS_UNSUPPORTED409The connected AI provider does not offer embeddings. Semantic search needs a provider that does.
APPROVAL_SELF_APPROVAL403The caller raised this approval request and cannot approve it themselves.
HANDLER_RUN_NO_PRINCIPAL409Run live executes as a principal of the app, and a console session is not one. Use the dry run, or call the endpoint as one of the app's users.
APPROVAL_CONSUMED409This approval was already used by another run of the same work. An approval runs its work once.
APPROVAL_ORG_REQUIRED403Approvals belong to an organization, and this caller has no active organization.
STEP_ALREADY_DECIDED409This approval step was already decided by another surface. Refresh to see the current state.
API_KEY_INVALID401The API key is missing, malformed, unknown, revoked, or expired. Returned identically for all five.

SDK-capability governance (notes/handler-sdk-capability-governance.md)

CodeStatusMeaning
SDK_CAP_NOT_GRANTED403You lack an SDK capability the handler's code uses. Request the capability to author it. details: { missing: [{ capability, label, risk, methods }], actor } — the capabilities required but not held.
DDL_NOT_DRY_RUNNABLE422A dry-run tried to execute schema-changing SQL. DDL cannot be rolled back, so it is never dry-runnable.
SDK_CAP_NOT_IN_MANIFEST403The handler called an SDK power absent from the manifest frozen at publish time. Republish to refresh it.
SDK_UNKNOWN_METHOD400The handler called an SDK method that does not exist. Check the spelling against the editor's autocomplete — the contract d.ts is the full surface.
LINK_TOKEN_INVALID404The link is invalid, expired, already used, revoked, or minted for a different purpose. Returned identically for all five.

Agent/arbiter charts (services/charts/chartSpec.js + the chart handlers)

CodeStatusMeaning
CHART_SPEC_INVALID422The chart spec failed structural validation. details: { issues: string[] } — the specific validation failures.
CHART_SNAPSHOT_TOO_LARGE413The chart is well-formed but its frozen data snapshot exceeds the storage/serve cap. details: { maxRows, maxBytes } — the caps that were exceeded.
CHART_NOT_FOUND404No such chart within your scope. Returned identically for a chart that does not exist and one owned by another organization.
CROSS_PLANE_FORBIDDEN403An app-plane caller tried to address another plane. An app may only touch its own database.
GRANT_EXCEEDS_HOLDER403You tried to grant capabilities you do not hold yourself. The response names which ones; ask someone who holds them, or have them granted to you first.
ROLE_PROTECTED400Built-in roles cannot be deleted. Create a custom role instead, or unbind this one from whoever holds it.

Agent run lifecycle (notes/agent-run-lifecycle-and-reliability-plan.md)

CodeStatusMeaning
AGENT_RUN_NOT_FOUND404No such agent run within your scope. Returned identically for a run that does not exist and one belonging to another organization.
AGENT_RUN_CONCURRENCY_LIMIT429The organization already has its maximum number of agent runs in flight. Retry after the interval in the Retry-After header. details: { limit, retryAfterSeconds } — the ceiling and when to retry.
AGENT_RUN_NOT_ACTIVE409That run has finished, so a message can no longer be sent to it. Send it to the conversation instead to start new work.
AGENT_SESSION_BUSY409This conversation already has a run in progress that you did not start. Wait for it to finish, or use a new conversation.
STALE_APPROVAL409The rows this approved step would change have changed since it was approved, so it was not run. Read them again and propose it afresh.
CHANGE_SET_NOT_FOUND404No recorded change with that handle in your runs. It may belong to someone else, or be older than the retention window.

Auth-method expansion (services/auth/*)

CodeStatusMeaning
OAUTH_PROVIDER_UNAVAILABLE400The sign-in provider is unknown or not configured on this deployment.

Sessions and tokens

CodeStatusMeaning
AUTH_TOKEN_EXPIRED401The access token has expired. Exchange the refresh token for a new pair, then retry.
AUTH_TOKEN_INVALID401The access token is not valid. Exchange the refresh token for a new pair, then retry.
REVERIFY_REQUIRED403A change that needs a fresh proof it is you (a new email, deleting the account) came without one, or with one that is spent, expired or another session's. Prove it with POST /auth/reverify and send its reverifyToken. details: { methods: Array<'password' | 'totp' | 'sms' | 'email'> }: the proofs this account can give.
PASSWORD_NOT_SET409The account has no password yet (it signs in with a provider or a sign-in link). Set one through the password reset email, which proves the address.
PASSWORD_INCORRECT403The current password given to change it is not the account's password.
EMAIL_UNCHANGED400The new email address is the one the account already has.
EMAIL_IN_USE409An email change could not finish: the new address got an account of its own after the change was asked for.
ACCOUNT_LAST_OWNER409The account is the last owner or admin of an org that still has other members, so deleting it would leave the org with nobody to manage it. Give another member the owner role, or remove the members, first. details: { orgs: Array<{ uid, name }> }
ACCOUNT_HAS_SUBSCRIPTION409The account still has a subscription that is billing it. Cancel it before deleting the account.
ACCOUNT_DELETE_DISABLED403The app's owner has not let accounts be deleted by their users. The owner can delete one from the console.
ACCOUNT_CHANGE_UNAVAILABLE400This change to an account is available to an app's own users, not to a console account.
EMAIL_NOT_VERIFIED403The account has not confirmed its email address yet: it cannot sign in with a password (when the app requires a confirmed address), send invitations or create organizations until it does. Resend the link with POST /auth/verify-email/request.
ORG_CREATION_DISABLED403The app's owner has not let its users create organizations beyond their own.
ORG_LIMIT_REACHED409The user has created as many organizations as the app allows.
ACCOUNT_DISABLED403The app's owner has disabled this account. It cannot sign in until the owner enables it again.
SESSION_ENDED401This session has ended. Sign in again. details: { reason: 'expired' | 'revoked' | 'reused' | 'signed_out' | 'invalid' | 'legacy' }
SESSION_IS_CURRENT409This is the session making the request. Use sign-out to end it.
TOKEN_PURPOSE_DENIED403This token was issued for one purpose and cannot be used for this request. details: { purpose: 'approver' }

Two-factor authentication

CodeStatusMeaning
MFA_REQUIRED401This account has two-factor authentication enabled. Answer the challenge to finish signing in.
MFA_CODE_INVALID400The submitted two-factor code did not match.
MFA_ALREADY_ENROLLED409A factor of this kind is already set up. Remove it before adding another.
MFA_NOT_ENROLLED400This account has no second factor set up.
MFA_LAST_FACTOR409This is the only method protecting the account, so it cannot be switched off.
MFA_ENROLLMENT_REQUIRED403This organization requires two-factor authentication. Set up a second factor to continue.
ORG_MFA_ENABLE_BLOCKED409Set up your own two-factor authentication before requiring it for the organization.
OAUTH_EMAIL_UNVERIFIED400The provider returned no verified email address, so the account cannot be matched safely.
OAUTH_SIGNUP_DISABLED400No account matches the verified address and sign-up via this provider is disabled.
OAUTH_EXCHANGE_FAILED400The token exchange or profile fetch failed at the provider. Usually transient — retry.
OAUTH_METHOD_DISABLED400This sign-in method is switched off for the account. Use another method or re-enable it in Settings.

Product tours

CodeStatusMeaning
TOUR_NO_SUBJECT401The request carries no signed-in principal, so there is no tour progress to read or record.
TOUR_INVALID_KEY400The tour key must be 1-64 characters of lowercase letters, digits, dot, underscore or hyphen, starting with a letter or digit.
TOUR_INVALID_VERSION400The tour version must be a positive integer.
TOUR_INVALID_STATUS400The tour status must be either completed or dismissed.

Console banners & announcements

CodeStatusMeaning
BANNER_NO_SUBJECT401Console notices are per person; sign in to read or dismiss them.
BANNER_INVALID_KEY400The banner key is not well formed.
BANNER_NOT_FOUND404That banner is not currently being shown to you, so it cannot be dismissed.
BANNER_NOT_DISMISSIBLE409That notice cannot be dismissed; it goes away when the condition it describes is resolved.
ANNOUNCEMENT_NO_ORG400Choose an organization first.
ANNOUNCEMENT_INVALID400The announcement is invalid: check severity, title length, the action link, and the dates.
ANNOUNCEMENT_NOT_FOUND404No announcement has that uid.
TOUR_LIMIT_REACHED409This account has recorded the maximum number of distinct tours; a new one cannot be added.

Registered 2026-11-04 (VERIFY §3 #12)

CodeStatusMeaning
ACTOR_CONTEXT_REQUIRED401This action needs a signed-in caller.
NO_MEMBER401This action needs a signed-in member.
NO_ACTIVE_MEMBER403No active member is signed in for this organization.
NO_ACTIVE_ORG403No active organization is selected. Choose one, then retry.
ORG_MEMBERSHIP_REQUIRED403You must be an accepted member of this organization.
ORG_NOT_FOUND404The active organization was not found.
ORG_NAME_REQUIRED400An organization name is required.
ORG_NAME_INVALID400That organization name is not usable.
MEMBERSHIP_UID_REQUIRED400Name the membership by its uid (membershipUid).
MEMBERSHIP_NOT_FOUND404No membership by that uid in the active organization.
MEMBERSHIP_SUBJECT_INVALID400The membership names a subject that cannot be used here.
LAST_PRIVILEGED_MEMBER_FORBIDDEN409The organization's last privileged member cannot be removed.
ORG_OWNER_REMOVAL_FORBIDDEN403The organization owner's membership cannot be removed.
OWN_ORG_LEAVE_FORBIDDEN403You cannot leave your own organization.
OWN_ORG_SELF_REMOVAL_FORBIDDEN403You cannot remove yourself from your own organization.
ORG_OWNER_AMBIGUOUS409The organization's owner could not be determined unambiguously.
CANNOT_INVITE_SELF400You cannot invite yourself.
INVITEE_EMAIL_REQUIRED400An invitee email is required.
INVITEE_EMAIL_ALREADY_EXISTS409An account with that email already exists. Invite the existing account instead.
INVITEE_ALREADY_MEMBER409That person is already a member of this organization.
INVITEE_SUBJECT_TYPE_MISMATCH400The invitee's account type must match yours.
INVITEE_SUBJECT_TYPE_UNSUPPORTED400That kind of account cannot be invited.
INVITATION_UID_REQUIRED400Name the invitation by its uid (invitationUid).
INVITATION_NOT_FOUND404No invitation by that uid.
INVITATION_NOT_PENDING409That invitation was already accepted, revoked or expired.
INVITATION_EXPIRED410That invitation has expired. Ask for a new one.
INVITATION_TARGET_MISMATCH403That invitation is addressed to a different account.
INVITATION_ORG_INVALID409That invitation has no usable organization.
INVITATION_ORG_CONTEXT_MISMATCH409That invitation belongs to a different organization than the active one.
INVITATION_SUBJECT_TYPE_INVALID409That invitation is for a kind of account this server does not support.
INVITED_ACCOUNT_CREATE_FAILED500The invited account could not be created. Retry, and contact support if it persists.
INVITED_ACCOUNT_ORG_CREATE_FAILED500The invited account's own organization could not be created. Retry.
ORG_INVITE_ONBOARDING_MODE_INVALID500The server is configured with an unknown invitation onboarding mode.
ORG_MEMBER_POLICY_MISSING500The baseline member policy is missing on this server; its migrations need to run.
APP_OUTSIDE_ORG403That app is not in your active organization. Switch to the organization that owns it.
APP_ORG_NOT_FOUND404No organization by that uid in this app.
APP_OWNER_ORG_NOT_FOUND404The organization that owns this app was not found.
NO_OWNER_TENANT404This organization has no owner account.
NO_TENANT404This organization is not billed.
NO_STAFF_ORG409This server has no staff organization yet; finish first-run setup.
CROSS_PLANE_UNVERIFIED403Platform code reached another app without passing its access check.
VALIDATION_ERROR400The request is not valid; the message says which field and why.
NOT_FOUND404Nothing by that uid.
ROLE_KEY_EXISTS409A role with that key already exists.
ROLES_KEY_NAME_REQUIRED400A role needs a key_name. To set only its display name, use the role actions.
BASE_ROLE_PROTECTED400An agent's or job's base role cannot be removed.
POLICY_NOT_FOUND404No policy by that uid.
AGENT_NOT_FOUND404No agent by that uid in the active organization.
AGENT_ROLE_MISSING500The agent role is not seeded in this app; its migrations need to run.
SELF_DELEGATION400An agent cannot delegate to itself.
AGENT_NO_LLM_BINDING409This agent has no AI connection of its own, and no included AI credits are available to it.
RUN_NOT_FOUND404No run by that uid in the active organization.
RUN_NO_PLAN409That run has no plan to act on.
PLAN_NOT_FOUND404No plan by that uid.
PLAN_STEP_NOT_FOUND404No plan step by that uid.
NO_PENDING_STEPS409That run has no steps waiting for a decision.
NOT_A_HANDOFF409That step did not hand off to an app agent.
NO_SESSION409That step has no conversation to hand off to.
SESSION_NOT_FOUND404No conversation by that uid.
APPROVAL_REJECTED409The approval this call waited on was rejected.
API_KEY_REVOKED409A revoked key cannot be rolled. Create a new key instead.
TOKEN_NOT_FOUND404No token by that uid.
CRON_NOT_FOUND404No scheduled job by that uid in the active organization.
CRON_RUN_NOT_FOUND404No run of that job by that uid.
CRON_SCHEDULE_INVALID400That schedule is not a valid cron expression.
CRON_PRINCIPAL_FAILED500The job's principal could not be created. Retry.
CRON_PRINCIPAL_MISSING409This job has no principal to bind a role to. Recreate the job.
HANDLER_DELEGATION_MISSING409The endpoint in front of this handler allows no SDK actions. Add the ones it uses to the endpoint's Allowed actions.
HANDLER_DEPENDENCY_DENIED403This handler may not call that SDK action for this caller.
HANDLER_DEPENDENCY_NOT_ALLOWED403That SDK action is not in the endpoint's Allowed actions.
HANDLER_NOT_PUBLISHED409Only a published handler runs live. Publish a version, or use a dry run.
HANDLER_UNSAFE_RAW_SQL400sdk.query was given something other than a string literal, or reached indirectly. Use a literal with ? placeholders, or sdk.sql.
HANDLER_DYNAMIC_MCP_ACCESS400The handler names an MCP server or tool dynamically. Write sdk.mcp.<alias>.<tool>() literally.
HANDLER_MCP_TOOL_UNKNOWN400The handler calls an MCP tool its connection does not have.
HANDLER_MCP_IN_TRANSACTION422The handler calls an external MCP tool inside withTransaction. Move the call outside it.
HANDLER_FILE_PATH_ESCAPE422A handler file path points outside the handler's own files.
HANDLER_VENDOR_FAILED422The handler's remote dependencies could not be vendored at publish.
HANDLER_VENDOR_UNAVAILABLE503Remote dependencies cannot be vendored right now. Retry the publish.
MCP_IN_TRANSACTION422sdk.mcp cannot be called inside withTransaction: an external call cannot be rolled back.
SDK_CALL_NOT_AWAITED500An SDK call was started but never awaited. Add await.
SDK_CONTRACT_MISSING500The server's SDK contract file is missing.
SDK_CRUD_UNAVAILABLE500The SDK's CRUD helpers are not available in this context.
SQL_INVALID_IDENTIFIER400sdk.sql.id() was given a name that is not a valid identifier.
SQL_UNDEFINED_BINDING400An sdk.sql template interpolated undefined. Pass null, or a value.
BULK_WRITE_UNFILTERED400updateWhere and deleteWhere need a filter, or { all: true } to change every row in scope.
ROW_VALUE_INVALID400A value does not fit its column (too long, out of range, the wrong type, or not one of its options); details.column names it.
READ_LIST_TOO_LARGE422This read would return more than 10,000 rows. Page through the table with sdk.readPage, or narrow it with filters.
BULK_LIMIT_EXCEEDED400Too many rows for one call; split it into smaller batches.
SOFT_DELETE_COLUMN_MISSING500A soft delete was asked for on a table without a deleted_at column.
AGG_SPEC_INVALID422The aggregate spec is invalid; issues names each problem.
UPLOAD_SOURCE_UNAVAILABLE502The URL to upload from could not be fetched.
ORG_REACH_UNRESOLVED500The caller's organization in this app could not be resolved.
AI_CODEGEN_BAD_INPUT400The handler-generation request is missing what it needs; the message says what.
AI_CODEGEN_EMPTY_PROMPT400Describe the handler to generate.
AI_CODEGEN_EMPTY_RESULT502The model returned no handler code. Rephrase and try again.
TABLE_READ_ONLY403This table is read-only in the data explorer.
TABLE_HAS_NO_UID409This table has no uid column, so its rows cannot be addressed one by one.
TABLE_HAS_DEPENDENTS409Other tables reference this one; remove those references first.
REDACTED_PLACEHOLDER_WRITE400"[redacted]" cannot be saved as a value. Clear the field and type the new one.
FK_PREFLIGHT_FAILED400A foreign key in the table definition does not resolve; the message names it.
PLAN_BLOCKED400This schema plan has blocking issues and cannot be applied.
FULL_SCHEMA_REQUIRED_BUT_UNAVAILABLE422Full schema details were asked for but could not be produced.
CSV_EMPTY400The CSV file is empty.
CSV_PARSE_FAILED400The CSV could not be parsed; the message says where.
CSV_TOO_LARGE413The CSV file is larger than this app allows.
CSV_TOO_MANY_ROWS413The CSV has more rows than this app allows in one import.
CSV_NO_HEADER400The CSV has no header row.
CSV_NO_ROWS400The CSV has a header but no data rows.
CSV_NO_MAPPED_COLUMNS400No CSV column maps to a writable column of this table.
CSV_UNKNOWN_COLUMNS400Some mapped columns do not exist on the table, or are not writable.
CSV_UNKNOWN_DEFAULTS400Some default columns do not exist on the table, or are not writable.
CSV_INVALID_DEFAULT400A default value cannot be stored in its column.
CSV_MISSING_REQUIRED_COLUMNS422The file does not supply every column the table requires; they are named.
CSV_ROWS_INVALID422Some rows hold values the table cannot store. Nothing was written; the errors say where.
STORAGE_REQUIRED400Name the storage by its uid (storageUid).
STORAGE_NOT_FOUND404No storage by that uid.
FOLDER_NOT_FOUND404No folder by that uid.
FOLDER_RACE_UNRESOLVED409The folder changed while it was being created. Retry.
FILE_NOT_FOUND404No file by that uid.
FILE_TOO_LARGE413The file is larger than this storage allows.
MIME_NOT_ALLOWED415This storage does not accept that file type.
INVALID_METADATA400File metadata must be a JSON object.
LLM_PROVIDER_UNSUPPORTED400That AI provider is not supported.
LLM_PROVIDER_NOT_ENABLED403That AI provider is not enabled on this server.
LLM_BASE_URL_REQUIRED400A self-hosted connection needs a base URL.
LLM_BASE_URL_INVALID400That base URL is not a valid address.
LLM_BASE_URL_NOT_ALLOWED400This provider does not take a custom endpoint URL.
LLM_CONNECTION_NO_CREDENTIAL409The AI connection has no stored credential.
LLM_CONNECTION_NO_KEY409The agent's AI connection has no usable key.
LLM_CONNECTION_UNAVAILABLE409No AI provider is connected. Connect one in Integrations.
MCP_ALIAS_IN_USE409That alias already names another MCP grant in this app.
MCP_CONNECTION_NOT_FOUND404No MCP connection by that uid.
MCP_GRANT_NOT_FOUND404No MCP grant by that alias.
NO_BILLING_ACCOUNT409This organization has no billing account yet.
NO_ACTIVE_SUBSCRIPTION409There is no live subscription to change.
NO_PLAN_LINE_ITEM409The subscription has no plan line to change.
PLAN_NOT_PURCHASABLE409That plan cannot be bought.
ADDON_NOT_FOUND404No add-on by that key.
ADDON_NOT_PURCHASABLE409That add-on cannot be bought on your plan.
ADDON_PAYMENT_FAILED402Your card could not be charged for the add-on, so it was not added. Update your payment method and retry.
NOT_APP_USER403Only an app's own users can buy through the app.
APP_USER_NOT_FOUND404No app user by that uid.
SUBSCRIPTION_NOT_FOUND404No subscription by that uid.
PRICE_IS_RECURRING400That price is a subscription; use subscription checkout.
PRICE_NOT_RECURRING400That price is one-time; use order checkout.
PRICE_SCOPE_MISMATCH403That price does not belong to this app.
PRODUCT_SCOPE_MISMATCH403That product does not belong to this app.
METADATA_TOO_LARGE400Product metadata is larger than Stripe allows.
CONNECTION_NOT_FOUND404Unknown Stripe connection.
NO_STRIPE_CONNECTION409No Stripe account is connected in that mode. Connect one first.
STRIPE_KEY_INVALID400Stripe rejected that key.
STRIPE_PACKAGE_MISSING500The server's Stripe library is missing.
WEBHOOK_SECRET_MISSING400The Stripe connection has no webhook secret.
WEBHOOK_PROVISION_FAILED502Stripe would not set up the webhook; the message says why.

On this page