Skip to content

Error codes

Every refusal is JSON:

{ "error": "human-readable explanation", "code": "MACHINE_READABLE" }

Switch on code, not on error — the wording may improve, the code will not change meaning.

This page is not every code. It explains the ones a person or an integration is likely to meet and has to act on. Each route’s own refusals, with their codes, are in the API reference under that route, and there are many more of those than are listed here.

Some refusals carry extra fields alongside those two: issues on a validation failure, template on a save conflict, balance when credits run out, missing when a bundle names something that does not exist.

The API takes any client. Its hostnames do not apply Cloudflare’s browser check, so a script with its HTTP library’s default User-Agent — Python’s urllib included — reaches the API like any other. A 403 whose body is plain text, error code: 1010, is not from the API: it is that check, on one of Sloose’s other hostnames (the app or the website), which keep it. Call the API’s own hostname, or send a User-Agent of your own if the request has to go through another of them.

These are a closed set. The app switches on them, and a code it has never seen is a dead end for whoever is reading it, so adding one is a deliberate act that ships with a release of the app.

Code Means What to do
LIMIT_RUNS The period’s import runs are used up. Dry runs still work. Wait for the period to roll over, or upgrade.
LIMIT_RUNS_CONCURRENT As many imports as the organisation’s plan runs at once are already running or starting in the organisation, and runsConcurrent says how many that is. Counted from the imports holding their claim, so one whose page was closed stops counting when its hold lapses, about two minutes later. Dry runs are not counted toward this limit and are never refused by it — though a dry run still holds its own import while it runs, so that import cannot start another run meanwhile (IMPORT_RUNNING). Wait for one of the other imports to finish, then run this one again. A plan with a higher number would allow more at once.
LIMIT_ROWS_PER_RUN Before the run: the import set is bigger than the plan allows in one run, and rowsPerRun says the most. During the run: every row is admitted before any of its records is written, and the write of the row that would cross the line is refused 403 RUN_STOPPED, whose stop carries this reason with rowsPerRun, rowsWrittenTotal and stoppedBy. Nothing reaches the CRM for that row. The line is the lower of the rows the run declared and the plan’s limit as it stands, so a plan changed under a running import applies to the rest of it, never below what is already written. The rows written before the stop are counted and kept, and the run is closed there. A progress report after it answers with the same stopped; the rowsWritten a report sends is accepted from older clients and does not meter anything. stoppedBy says which line bound: plan, or declaration when the run tried to write more rows than it declared for itself. Before the run, and for stoppedBy: "plan": split the file, narrow the row range on Run, or upgrade. For stoppedBy: "declaration" the run tried to write more rows than it declared for itself, which upgrading cannot change — tell support.
LIMIT_CONNECTORS One more connection would exceed the plan’s number of connections. A Zoho sandbox counts like any other. Disconnect one, or upgrade.
LIMIT_ROWS Server-run imports only: the run would exceed the monthly row allowance. Not returned yet: the month’s rows are counted and never enforced, on any plan. Nothing today. (Some plans price rows past the allowance per thousand; nothing in Sloose switches that on today — see Plans and limits.)
LIMIT_SCHEDULES The plan’s schedule limit is reached. Not returned yet: schedules are stored but not run, and the limit arrives with scheduled imports. Remove a schedule, or upgrade.
LIMIT_CRM_USERS Active CRM users exceed the plan’s band. Nothing to do unless you want the numbers to agree: Usage & credits shows the CRM’s size beside the plan’s, and a larger plan is sized for it. This is a warning, never a block — a fifty-seat CRM where two people import is still that CRM’s size.
LIMIT_FILES_BYTES The files the organisation stores at once would pass what the plan holds (1 GB on Free, 10 on Team, 100 on Business, 500 on Enterprise). Only a NEW upload is refused; nothing stored is deleted early. Returned when an upload is reserved (POST …/imports/{id}/files), with usedBytes and maxBytes. Delete files you no longer need, wait for them to expire (7 days after last use on Free, 30 on the others), or upgrade.
LIMIT_FILE_SIZE One file is larger than a file may be: the lower of 5 GB and the maximum an administrator set. Returned when an upload is reserved, with maxFileBytes. Split it, or ask an administrator to raise the organisation’s per-file maximum (never above 5 GB).
FEATURE_SHARED_TEMPLATES The plan cannot share templates across the organisation. Keep the template private, or upgrade.
FEATURE_HELPER_LIBRARIES The plan cannot use helper libraries. Upgrade.
FEATURE_SERVER_RUN The plan cannot run imports server-side. Not returned yet: nothing runs an import on the server, on any plan. Nothing: an import runs in your browser on every plan.
FEATURE_MCP The plan cannot use the MCP server. Upgrade.
FEATURE_ROLLBACK The plan cannot roll a run back. Not returned yet: Sloose has no way to undo a run, on any plan. Nothing: a dry run before the real one is the check there is.
FEATURE_SCHEDULED_IMPORTS The plan cannot schedule imports. Not returned yet, for the same reason as LIMIT_SCHEDULES. Upgrade.
CREDITS_EXHAUSTED No AI credits left. The response carries balance. Buy a credit pack, or wait for the period to roll over.
STATUS_SUSPENDED The subscription is suspended, and this was a real run: its authorisation is refused. Reads still work, templates, imports and configuration can still be edited, and a dry run still runs. (An AI request is refused 402 SUSPENDED.) Settle the account.
STATUS_PAST_DUE A payment is overdue (a card payment failed, or an invoice passed its due date) and the grace period is running. Never a refusal: it is among the warnings of the organisation’s entitlements while the grace period runs. Pay the invoice or update the card before the grace period ends.

An AI request refused for credits (CREDITS_EXHAUSTED) or for a suspended organisation (SUSPENDED) is a 402 and carries the credit balance. A card declined on a change of plan is a 402 too, CARD_DECLINED, and carries none. STATUS_SUSPENDED is how a run is refused, a 403.

Code Status Means
AUTH_REQUIRED 401 No bearer, or one that does not verify.
TOKEN_REVOKED 401 The API token was revoked.
TOKEN_EXPIRED 401 The API token passed its expiry.
MEMBERSHIP_GONE 401 / 403 An API token whose creator is no longer a member of the organisation (401), or a request whose membership went while it was being answered (403). A person removed from an organisation is not signed out: their session is left in no organisation, and is refused 403 NO_ORG there.
ROLE_REQUIRED 403 Your role is too low. The response names the role needed.
ORG_MISMATCH 403 The bearer was issued for a different organisation.
NOT_YOURS 403 The import is somebody else’s and your role cannot do this to it: an operator changes, runs and deletes only an import they started, and a builder deletes only their own. Ask whoever started it, or an administrator. See the roles.
SESSION_REQUIRED 403 An API token was used on a session-only route. See Authentication.
ADMIN_REQUIRED 403 A backoffice route (/staff, any …/admin) called with anything but a staff member’s session or the operator token: an organisation’s API token, say, or a customer’s session, however senior.
ROLE_CHANGED 403 The role dropped below what this route needs, since the token was issued. Refresh the session.
CONSENT_REVOKED 401 An MCP token whose grant has been revoked: by the person who allowed it (Your account → Apps with access), or by an administrator (Settings → Apps with access). Sign in through the client again.
CURRENT_SESSION 409 DELETE /auth/account/sessions/{id} named the session asking. Sign out instead.
SECOND_FACTOR_REQUIRED 403 A staff route, and this session has no recent second factor. enrolled: false means none is set up (Your account); enrolled: true means pass it at /second-factor. Also answered when a factor is enrolled and a session that has not passed one recently tries to add or remove a factor, or to delete the account.
STAFF_VIEW 403 The session is a staff member’s view of an organisation, and this acts on the person rather than the organisation. Their own account and second factor are refused to a view, reading and writing alike; and any view — read-only or write-capable — makes none of their writes outside the organisation: making an organisation, accepting an invitation, asking another organisation for access, ending one of their sessions, moving the session.
IMPERSONATION_READ_ONLY 403 The session is a read-only staff view of an organisation, and this request is not a read. Refreshing the view and ending it are the two exceptions.
IMPERSONATION_REFUSED 403 The session is a write-capable staff view of an organisation (a read-only one is refused IMPERSONATION_READ_ONLY before this), and this would grant a credential or access that outlasts the view, or end the organisation: minting an API token, inviting somebody, approving an access request, raising a member’s role, or closing the organisation — or would spend or change the organisation’s money: a Checkout, the Customer Portal, the one-click top-up’s settings, overage, or a trial. Staff close an organisation, grant credits and start a trial from the backoffice, which records who did it. Connecting an app to the organisation in the member’s name is refused the same way, as OAuth’s access_denied.
STEP_REQUIRED 403 One of Better Auth’s own two-factor endpoints was called directly; they are reached through /auth/second-factor.
SECOND_FACTOR_LOCKED 429 Five wrong codes; the step is locked until until.
INVALID_CODE 401 / 400 The authenticator or backup code was not right: 401 at the step (/auth/second-factor/verify), 400 for the first code of an enrolment, where the session is fine and the page shows it inline.
TOTP_NOT_ENABLED 400 No authenticator app is enrolled for this person.
Code Status Means
INVALID_BODY 400 The body did not match the schema. issues carries the list.
BAD_INPUT 400 The same thing, on the AI routes, which use their own code.
UNKNOWN_MODULES 422 A module reference is not in the latest discovery. missing names them. A bundle’s template enabling a module the connection has, but that the push leaves unoffered, is not refused: it is stored and named in the push’s warnings.
KEY_CLASH 422 Another module already uses that key or singular name.
NAMESPACE_MISMATCH 422 A helper manifest’s namespace does not match the path it was written to.
EXPIRY_IN_PAST 422 A token expiry that has already passed.
NOT_UTF8 422 A delimited file sent to an import is not valid all the way through in the encoding its start decided (its byte-order mark, or UTF-8 in its first 64 KiB). Its later accented characters would have been replaced; nothing was stored. Save it as UTF-8 (in Excel, “CSV UTF-8”) and send it again. A file that is not UTF-8 from the start is not refused: it is read as the legacy encoding its bytes look like, and the upload’s read says which and that it was a guess.
TOO_MANY_FILES 400 A records write names more files than one request may: up to 250 for one record, its subform rows’ files included, and up to 20 between the records of a batch. most says the limit and files how many the request named. written: false: nothing was admitted or sent. Sloose’s own import sends a batch’s records in more requests to stay under it, so a run meets it only for one record that names more than 250. Send fewer records in each request; a single record past 250 files cannot be written in one request.
RATE_LIMITED 429 Too many of something in a while, with retryAfterSeconds. On POST /orgs it is organisations made: one person may make ten in 24 hours and twenty in 30 days, closed ones counted, and error says which and about how long to wait.
INVALID_TEMPLATE 422 A template configuration that does not validate. issues carries the list.
TEMPLATE_CONFLICT 409 Somebody else saved the template first. The response includes their version so you can show the difference rather than overwrite it.
TEMPLATE_MANAGED 409 A configuration repository owns the template, so the change belongs there: the next push would overwrite it. sourceRef names the file. Its visibility can still be changed.
TEMPLATE_MOVED 409 The template has moved on since the import copied it, so updating it from the import would overwrite a version nobody here has seen. version, updatedBy and updatedAt say where it is now; take the latest, or save the import as a new template.
FROM_FUTURE 409 The document was written by a newer build than this server. Stored shapes are migrated forward, never backward.
RUN_RETIRED 409 A retry named a run that is past its plan’s history, removed or being removed. What that run made can no longer be read in full, so a retry could write some of it again. A name that finds no run of the organisation gets the same answer, since a removed run leaves nothing behind to tell it from one that never existed. Run the import again instead.

Every request about one connection names it — ?connector=<id> on a route, connectorId in a body, connection on an MCP tool — even in an organisation that holds only one. Nothing picks one for a request that does not say, because an organisation may hold a client’s CRM each, and writing to the wrong one is the mistake that cannot be taken back.

Code Status Means
CONNECTION_REQUIRED 400 The request named no connection. connections lists the ones this bearer may name, each with its id, label and kind — empty when the organisation holds none yet.
CONNECTION_NOT_FOUND 404 The connection named is not one this bearer may use: another organisation’s, another person’s own, or none at all. The answer is the same for each.
NO_CONNECTION 409 A run was asked for an import that names no connection yet. Choose one on its Target.
RUN_CONNECTOR_MISMATCH 409 A record write named a different connection from the one its run was authorised for.
DESTINATION_ALLOWANCE_SPENT 403 A run that writes was asked for while the connection’s CRM is refusing calls because its API credits for the last 24 hours are spent. The run was not started: nothing was claimed, counted or recorded. error is a sentence to show as it is, and spentAt is when Sloose first heard. A dry run is not refused, and nor is any run while Sloose cannot tell (it gives up asking after two seconds and authorises). Not one of the plan’s reasons above: no plan changes it. GET /orgs/{org}/connectors/{id}/credits says whether it still holds (spent), and POST …/credits/check asks the CRM first. Zoho names no time at which credits return.
DAILY_ALLOWANCE_SPENT 429 A call to the CRM was not sent, because the CRM has said its API credits for the last 24 hours are spent. While that holds Sloose refuses the CRM’s calls itself and lets one a minute through to ask again; the first one Zoho does as asked ends it. On a write the body says written: false. There is no Retry-After. The call that first met the limit is relayed as Zoho’s own 429, with zoho.quotaSpent: true.
MODULE_NOT_FOUND 404 A records route named a module the connection does not have, as its last discovery read it (in any letter case: accounts is Accounts). Only a connection’s own modules are asked of the CRM. A module added to the CRM since the connection was made is read with Read again on the connection’s Overview, under Connections.

Changing who may do what has its own rules — see People and roles.

Code Status Means
SELF_CHANGE 403 You tried to raise your own role, or change your own membership. Lowering your own role is allowed.
OUTRANKED 403 You cannot change somebody above you, or grant a role above your own.
LAST_OWNER 409 The change would leave the organisation with no owner — leaving it included. Make somebody else an owner first, or close the organisation.
MEMBER_CHANGED 409 The member’s role changed between your reading it and your request. Read it again and decide afresh. (Removed in between, they are MEMBER_NOT_FOUND.)
MEMBER_NOT_FOUND 404 That person is not in this organisation.
Code Status Means
CONFIRMATION_MISMATCH 400 Deleting the account, and confirm was not the account’s own email.
SOLE_OWNER 409 Deleting the account of the only owner of an open organisation. orgs names each: close it, or make someone else an owner, first.
LAST_STAFF 409 The last staff member cannot be deleted, nor have the role taken away.
STAFF_CANNOT_BE_DELETED 409 Staff deleting a staff member’s account. Take the role away first.
Code Status Means
DISCOVERY_FAILED 502 The CRM could not be read. The message says why, bounded to 500 characters.
Code Status Means
AI_REFUSED 422 The model declined. category says why.
AI_BAD_OUTPUT 502 The model answered, but not with something usable.
AI_NOT_CONFIGURED 503 AI is not configured on this deployment. Unconfigured paths say so rather than failing obscurely.
AI_UNAVAILABLE 503 The model could not be asked just now: the AI service is out of capacity, rate limited or down. Nothing was changed and nothing was charged; send the same request again shortly. Over MCP, the tool answers it as an error with the same code and words.
ORG_NOT_CONFIGURED 409 The organisation has no module registry yet. Run discovery and enable a module first.
SESSION_FORBIDDEN 403 That chat session belongs to somebody else.
SESSION_NOT_FOUND 404 sessionId names no chat session in this organisation — including one the history window has deleted. Leave sessionId out to start a new one.

404 with a *_NOT_FOUND code — TEMPLATE_NOT_FOUND, MODULE_NOT_FOUND, FIELD_NOT_FOUND, LIBRARY_NOT_FOUND, SCHEDULE_NOT_FOUND, TOKEN_NOT_FOUND, ORG_NOT_FOUND.

A template you cannot see answers 404 rather than 403, deliberately: whether a private template exists is not something another member should be able to probe for.

Report a problem with this page

sloose.com