Refusal codes
Every refusal carries three things: a code to branch on, a message a person can read, and a hint naming the next call that would succeed. Identical over REST and MCP, because both are the same service.
{ "code": "GATE_NOT_PASSED", "message": "Stage Launch is gated. Gate LAUNCH-1 is OPEN with 4 of 5 conditions met.", "hint": "Satisfy the conditions, then call evaluate_gate id=gt_41c."}Domain codes
A rule the product is enforcing. The hint tells you how to satisfy it.
GATE_NOT_PASSEDA gate is standing between you and this action, and at least one of its conditions is open.
What to do: The message names the gate and counts its conditions; the hint names the unmet ones and the exact call that closes them. Satisfy them, then call evaluate_gate.
BLOCKED_BY_DECISIONAn open decision is holding this work. Someone has to make the call first.
What to do: The hint names the decision. Resolve it with decide_decision - which only a person can do.
AGENT_ACTION_DENIEDAn agent principal attempted a protected act. Creating tenants, changing membership, registering agents, resolving decisions and every hard delete are refused to agents whatever their token grants.
What to do: No scope enables this - widening the token will not help. A person performs it, in the app or with their own credentials.
INSUFFICIENT_SCOPEThe token does not carry a scope this tool requires.
What to do: Mint a token with the scope named in the message. The scope reference lists what each one unlocks.
PLAN_LIMIT_REACHEDA ceiling on the current plan. The next create was refused; nothing that already exists was removed, hidden or degraded.
What to do: The message names the limit, the live count, what was counted and where the ceiling came from. Archive something you are done with - that frees the slot - or move up a plan.
PLAN_FEATURE_REQUIREDThe capability is not included in this plan at all. Distinct from a ceiling: retrying can never succeed.
What to do: The message names the cheapest plan that includes it. Everything already recorded stays exactly where it is.
CREDITS_EXHAUSTEDNot enough agent credits for a metered call. Credits pay for the one operation that runs a model - semantic search.
What to do: Every unmetered call still works: the board, decisions, documents, logs and context are free. Top up, or use keyword search instead of semantic.
POOL_EXHAUSTEDEvery value in the pool is held. Nothing was taken and nothing already held was disturbed.
What to do: The message names the capacity, how many are held and how many you asked for. Release something you are done with (release_resource), or widen the pool - which is a human act, done in Settings.
VALUE_NOT_IN_POOLThe value is not one this pool contains - out of its ranges, or not a well-formed value of its kind. Also raised when releasing something that is not currently held.
What to do: Read the pool with get_resource_pool: it lists what the pool actually contains.
VALUE_ALREADY_HELDSomebody holds the value you asked for. It is never silently substituted - a port you did not choose is worse than a refusal you can act on.
What to do: The message names the holder when the record knows it. Ask for a different value, allocate without `preferred` to get the lowest free one, or take it up with whoever holds it.
POOL_KIND_UNKNOWNThe pool declares a kind this build does not register, so its values cannot be interpreted. Nothing about the pool was changed.
What to do: This is not something a caller can fix by retrying or by sending different arguments. The message names the kinds this server does register.
SITE_UNKNOWN_SECTIONThe site has no such section. The sections are a registry in this build, not free text.
What to do: The message names every section this server has. Pick one of them.
SITE_UNKNOWN_ENTITY_TYPEThat kind of thing cannot be placed on a site at all.
What to do: The message names the kinds that can. Nothing was changed.
SITE_SECTION_REJECTS_TYPEThe kind and the section do not go together - a release in `legal`, a product in `blog`. Refused rather than stored, because a site reads a section expecting a shape and one row of the wrong kind renders as a fault or an invented page.
What to do: The hint names the sections this kind of thing CAN go in, or what the section admits when it admits nothing of this kind.
SITE_CROSS_WORKSPACEThe thing being placed lives in a different workspace from the site. A placement is workspace-scoped and would have to belong to two.
What to do: Place something from the site's own workspace, or move the record there first. This is a boundary, not a permission - widening it is a design decision rather than a setting.
SITE_NAME_AMBIGUOUSMore than one product you can see is called that, so naming the site by name does not identify one. Nothing was changed.
What to do: The hint lists the ids of every match. Pass one of them instead of the name.
INVENTORY_KIND_UNKNOWNThe inventory records a fixed set of kinds of holding, and that is not one of them. The set is a registry in this build, not free text.
What to do: The message names every kind this server registers. A kind arrives by being added to the build, so this is not something a retry or different arguments can fix.
INVENTORY_VALUE_MALFORMEDThe value is not a well-formed one of its kind, so it was refused rather than stored in a spelling nothing else would match.
What to do: The hint says what a value of this kind looks like. A domain is a hostname - no path, no credentials, and not an IP address.
INVENTORY_ALREADY_HELDYou already hold that value. One live holding per value is a database constraint, not a check that can be raced past.
What to do: The message names the existing holding. Update it instead of adding a second, or release the old one first if this is a re-acquisition.
INVENTORY_RELEASEDThe holding has been released - you do not own it any more - so it cannot be assigned, re-costed or given a new renewal date. The record stays readable on purpose.
What to do: The message says when it was released and why. If you have it again, record it as a new holding; the old row remains as the history of having had it.
IDEA_ALREADY_CONVERTEDThat idea has already become a product. Converting again would create a second product from one idea and leave two records claiming the same origin.
What to do: The message names the product it became. Work on that product, or capture a new idea if this is genuinely a different one.
SPEND_CAP_EXCEEDEDThis write would take the window's spend past the cap set for it.
What to do: Wait for the window to roll over, or raise the cap. Reads are unaffected.
BILLING_NOT_CONFIGUREDThis installation is not connected to a payment provider, so nothing can be bought on it.
What to do: Nothing is wrong with the organization - every plan limit and every record still behaves exactly as before. Only a purchase is refused.
PLAN_NOT_PURCHASABLEThat plan cannot be checked out: either it is the free plan, which is what you are on when you have bought nothing, or nobody has mapped it to a price here.
What to do: get_subscription returns the plan catalog. Another plan may still be purchasable.
SUBSCRIPTION_EXISTSThe organization already holds a subscription that entitles it. One organization holds one - a second would bill twice and only one of them would be recorded.
What to do: Changing the plan or the seat count is not available yet - the payment provider's own portal cannot do it either. End the current subscription from the billing page and buy the one you want. A canceled or paused subscription does not refuse a new purchase.
NO_SUBSCRIPTIONThere is no subscription to act on. The organization is on the free plan, or it holds a record the payment provider knows nothing about.
What to do: Nothing is wrong. Start a subscription from the billing page if you want a paid plan.
SUBSCRIPTION_ENDEDThe subscription is already over. A finished subscription can never be reinstated by the provider.
What to do: Buy again from the billing page - the record is kept, so the purchase lands on the same customer rather than a new one. Nothing was deleted when it ended.
PROVIDER_UNAVAILABLEThe payment provider did not answer, or refused to open the checkout.
What to do: Nothing was bought and nothing about the organization changed. Try again in a moment; the provider stated a reason and it is in the server log.
PRODUCT_READ_ONLYThis product is outside the organization's product limit, so it accepts no writes. It is not deleted, not hidden and not degraded: every read works, the whole history is there, and export works exactly as before.
What to do: An owner or admin chooses which products keep writing, on the reconciliation screen the refusal names - picking this one releases it and restricts another. Moving up a plan releases every one of them at once. The message says how long the extras stay before they are archived, and archiving is recoverable too.
PROMO_INVALIDThe code does not open anything. It is unknown, or it was withdrawn by whoever made it - deliberately the same answer for both, so the refusal cannot be used to find out which codes are real.
What to do: Check it against what you were sent: the shape is MM-XXXXX-XXXXX-XXXXX-XXXXX, case does not matter, and I, L and O are read as 1, 1 and 0. Your plan is untouched either way.
PROMO_EXPIREDThe code was real and its validity has run out.
What to do: Nothing about the organization changed. Ask whoever sent it whether there is a current one.
PROMO_EXHAUSTEDThe code has already been redeemed as many times as it was made for.
What to do: It was a real code and it has run out - this is not something you did wrong and not a limit you hit. The plan is exactly what it was.
PROMO_ALREADY_REDEEMEDThis organization has already used this code. A code counts once per organization, not once per person, so a colleague may have used it.
What to do: The plan it granted is already in force, or has since run its course - the billing page shows what is active and until when. Entering it again would not add time.
ENTITY_CHANGEDSomebody else changed this record after you read it, so your write was refused rather than applied on top. Nothing was overwritten and nothing was lost.
What to do: Re-read the record and re-apply your change. The refusal names WHICH fields moved (never their values) and when, so a caller writing different fields can simply retry. Omitting `expectedVersion` skips this check entirely - which is the right choice for a one-shot write and the wrong one for an editor.
SIGNUP_CLOSEDThis installation is not accepting new accounts at all right now. It is a switch somebody set, not a judgement about you.
What to do: Nothing about your details is wrong and no code would help. An account that already exists still signs in normally. Ask whoever runs the installation when it reopens.
INVITE_REQUIREDSignup here is invite-only, and the request carried no code.
What to do: Ask somebody who already has an account - every account comes with invites to give away. The code is a bearer code, so they can simply pass it to you.
INVITE_INVALIDThat code does not open the door. It is unknown, or it was withdrawn by the person who made it - deliberately the same answer for both, so the refusal cannot be used to find out which codes are real.
What to do: Check it against what you were sent: the shape is MM-XXXXX-XXXXX-XXXXX-XXXXX, case does not matter, and the letters I, L and O are read as 1, 1 and 0. If it still fails, ask for a new one.
INVITE_EXPIREDThe code was real and its validity has run out.
What to do: Ask whoever sent it for a fresh one - generating another takes them a moment, and this is not a limit they have hit.
INVITE_EXHAUSTEDThe code has already brought in as many accounts as it was made for.
What to do: Ask for a new code. Nothing about the account it created is affected, and the person who sent it has not lost anything else.
INVITE_QUOTA_REACHEDYou are holding as many invites as your quota allows. The refusal names the ceiling, how many you are using and exactly what was counted.
What to do: Revoke an invite nobody has used and the slot comes back immediately. An invite that has already brought somebody in is spent and stays spent - revoking it would not un-create their account.
PASSWORD_NOT_SETThis account has no password at all, so the password form has nothing to check. It was opened through an external account - the refusal names which one - and that is how it is opened.
What to do: Use the sign-in button for the provider named in the message. Once you are in, Settings lets you add a password as a second way in if you want one. Note that this refusal, unlike every other answer the sign-in form gives, confirms an account with that address exists - it is answered honestly on purpose, because there is no password reset to fall back on.
OAUTH_NOT_CONFIGUREDThis installation cannot complete a sign-in with that provider - either it does not know the provider at all, or its credentials were never filled in.
What to do: Use one of the buttons the sign-in screen actually offers, or a password. Nothing you can do at the provider changes this; it is configuration on this server.
OAUTH_STATE_INVALIDThe sign-in that came back could not be shown to be the one that started in this browser. Every way that can happen - the attempt sat too long, the tab was reopened from history, the cookie was cleared, the link was opened somewhere else - gives this same answer, on purpose: telling one apart from another only helps somebody probing.
What to do: Start the sign-in again from the beginning. Nothing was created and nothing was linked.
OAUTH_EXCHANGE_FAILEDThe provider was reached and did not give us an account to work with - it declined the exchange, or it did not answer in time.
What to do: Try again in a moment. If it keeps happening, sign in with a password if you have one; the provider being unavailable does not affect anything about your account.
OAUTH_EMAIL_UNVERIFIEDThe provider would not vouch for the email address on that account, so it cannot be used to reach a makermap account. Accepting it would let anybody claim an address by typing it into a new provider account.
What to do: Verify the address at the provider and try again - on GitHub, also make sure you granted access to your email addresses. If you already have a makermap account, sign in the usual way first and connect the provider from Settings, which proves the account is yours.
OAUTH_ALREADY_LINKEDThat provider account already opens a different makermap account.
What to do: Sign in with it instead of connecting it, or disconnect it from the other account first. It is never moved automatically - doing that would take a way in away from an account that has it, possibly its only one.
OAUTH_ACCOUNT_CLOSEDThe makermap account that provider account belongs to has been closed.
What to do: Nothing here reopens it. Ask whoever runs the installation.
USER_IDENTITY_NOT_FOUNDNo connected account of yours has that id.
What to do: Re-read the list and use an id from it. An identity belonging to somebody else answers the same way, deliberately - the alternative is a way of testing whether an id exists.
LAST_SIGN_IN_METHODDisconnecting that provider would leave the account with no way to sign in at all - it is the only one, and the account has no password.
What to do: Connect a second provider first, then disconnect this one. The refusal is not a formality: there is no password reset in this product, so an account with no key left is unreachable rather than inconvenient.
OAUTH_FAILEDA sign-in through a provider failed for a reason this build could not name. It is the honest answer of a fallback, not a description.
What to do: Try again. If it repeats, the server log holds the real cause - this code exists so a failure still lands you on a page rather than on a blank error.
PLATFORM_SETTING_UNKNOWNA platform setting was addressed by a name this build does not have in its registry.
What to do: The hint lists the settings that exist. A name that is not one of them is refused rather than stored, because a value nothing reads is indistinguishable from a feature that does not work.
PLATFORM_SETTING_INVALIDThe setting exists and the value is not one it accepts.
What to do: The hint states what the setting accepts. Nothing was written.
GRANT_REASON_REQUIREDA plan was granted with no explanation. The field is required and whitespace does not count as one.
What to do: Say what the grant is for - a design partner, a launch compensation, the founder's own installation. A year from now the row has to explain itself without anybody remembering.
PLAN_NOT_GRANTABLEThe grant names a plan that is not in this build's registry.
What to do: The hint lists the plans that exist. Nothing was written.
VALIDATION_ERRORThe arguments are well formed but the values are not usable - out of range, mutually exclusive, or referring to something that cannot be used that way.
What to do: The message names the field and the constraint. This is not a schema error; the shape was accepted.
WORKSPACE_ORG_MISMATCHThe workspace and the organization named in the same call belong to different tenants.
What to do: Pass the workspace alone and let the organization be derived from it.
SELF_DEPENDENCYSomething was asked to depend on itself.
What to do: Check the two ids in the call - they are the same.
DEPENDENCY_CYCLEThe edge would close a cycle in the temporal graph, so no ordering could satisfy it.
What to do: The message names the path. Remove one edge along it first.
INVALID_TARGETThe target exists but is not a thing this operation can be applied to.
What to do: The message says what kind of target is expected.
ALREADY_FORMALIZEDA captured block has already been turned into a task, epic, milestone or initiative.
What to do: Open what it became - the message names it. A capture formalizes once.
PRODUCT_NOT_SOFT_DELETEDrestore_product was called on a product that was never deleted.
What to do: Nothing to restore. If it is missing from a list, it is probably archived rather than deleted.
NO_COLUMNSThe board has no columns, so there is nowhere to put a task.
What to do: Create a column with create_board_column first.
DESIGN_SPEC_INVALIDA design spec did not satisfy the DSL.
What to do: The message carries the offending path. Fix that node rather than resending the whole document.
DESIGN_VARIANT_NOT_CHOSENA design review cannot close because no variant has been chosen.
What to do: Choose one, then close. Which variant ships is a decision, not a default.
UNKNOWN_BLOCK_TYPEA design spec used a block type the DSL does not define.
What to do: The message lists the block types that exist.
TOKEN_KEY_UNKNOWNA design spec referenced a design token that does not exist.
What to do: The message lists the valid keys.
TOKEN_VALUE_INVALIDA design token was given a value outside its allowed set.
What to do: The message names the constraint.
Transport codes
Derived from the HTTP status when no domain code was attached. Getting one of these where a domain rule was clearly being enforced means the code is missing - a bug worth reporting.
INVALID_REQUESTThe request was rejected and no domain code was attached - usually a malformed body or a failed schema.
What to do: Check the arguments against the tool schema. If the message describes a domain rule rather than a shape, the missing code is a bug worth reporting.
UNAUTHENTICATEDNo usable credential. The token is missing, malformed, revoked or expired.
What to do: Check the Authorization header carries the whole token, then mint a new one.
FORBIDDENAuthenticated, but not permitted to reach this tenant or record.
What to do: Check which workspace the record lives in and which the token can reach.
NOT_FOUNDNo such record - or none the caller is allowed to see. The two are deliberately indistinguishable.
What to do: Confirm the id and the workspace. A record in another workspace answers exactly like one that does not exist.
CONFLICTThe write collides with the current state - typically a name or slug already in use.
What to do: Re-read and retry with a different value. The message says what collided. A record that MOVED under you is the separate, named ENTITY_CHANGED.
ERRORAn unexpected failure with no status to derive from. This is the only code that means "we do not know".
What to do: Retry once. If it repeats, it is a bug.
If you are reading a refusal and still do not know what to do, that is a defect in the refusal and worth reporting as one. See also troubleshooting.