MainSDK
Search⌘K
Docs

Check codes

Every MAIN- code the specs define so far, grouped by area, with where you meet it, what it means and how to fix it.

Planned for 0.2

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

Every finding from mainsdk check and every error the SDK raises carries a stable code: MAIN-<AREA>-<NNNN>. A code is assigned once and never reused or changed in meaning. Each one has a page at https://mainsdk.dev/errors/<code>, which is also the type of its problem details.

Look any code up offline:

text
$ npx mainsdk explain MAIN-DATA-0007
MAIN-DATA-0007  Record belongs to another user  (403)
cause  A query read a record owned by a different user.
fix    Scope the query with db.orders.for(user).

The Raised by column says where you meet the code: check (a gate finding before merge), runtime (an error or log from the SDK in your running app), or CLI (a command that refuses to run). A code not listed here is not defined yet. A family written MAIN-<AREA>-* is a group of Main 27 rules whose individual numbers arrive with the baseline pack.

CHECK, CONFIG and CONTRACT

CodeRaised byMeaningFix
MAIN-CHECK-0026checkAn interface resolves to a local driver in productionSet a real driver in main.env.prod.yaml
MAIN-CONFIG-0001check, runtimeUnsupported schema value in main.yamlUse schema: 1; the error lists supported versions
MAIN-CONFIG-0002check, runtimemain.yaml can't be read: bad indent, a tab, an anchor or tag, or a duplicate key; the error names the lineFix the YAML at that line; main.yaml uses plain maps, lists and scalars
MAIN-CONFIG-0003check, runtimeA value has the wrong format: money ("$0.05"), a rate ($5/day), a size (25MB) or a duration (1h)Write the value in the format the error shows
MAIN-CONFIG-0005check, runtimeNo main.yaml in the project folderRun npx mainsdk init
MAIN-CONFIG-0004check, runtimeA literal value in a field marked secretUse a secret: reference, for example secret:RESEND_API_KEY
MAIN-CONFIG-0010check, runtimeA layer weakens its parent, for example adds a host main.org.yaml doesn't allowRemove the change, or add an exception with rule, reason, owner and expiry
MAIN-CONFIG-0020runtimeA config value fails its schema; the last good value is keptFix the value in your config store
MAIN-CONFIG-0021runtimeA pushed main. value is looser than main.yaml allows, or a limit's period differs; the value is refused and the last good one keptPush a value equal to or tighter than main.yaml, or change main.yaml in a reviewed deploy
MAIN-CONFIG-0022runtimeA pushed key starts with main. but names a path that can't be pushed, such as main.payments.driver; the key is refusedChange that setting in main.yaml in a reviewed deploy
MAIN-CONFIG-0023runtimeThe config store can't be read (down, or a load timed out); the app serves its last good values, logged once per outageRestore the store; the app needs no restart
MAIN-CONTRACT-0003CLINo driver version satisfies every interface range during syncWiden a range or pick a driver that implements it; the error names both ranges
MAIN-CONTRACT-0021CLIA contract has no threat model (mainsdk contract check)Add the interface's STRIDE threat model
MAIN-CONTRACT-0030CLIThe vendored getqr.id openapi.yaml doesn't match the sha256 in its vendor.yaml, or the generated TypeSpec import is stale (ADR-0057)Restore the vendored file and take a new version only through contract diff --vendor getqr; rebuild with contracts:build
MAIN-CONTRACT-0031CLIcontract diff --vendor getqr found an upstream change that breaks an operation or field MainSDK uses; the finding names bothKeep the pin until the call is updated in the same pull request, or ask the GetQR ID team
MAIN-CORE-0001runtimeNative core ABI version doesn't match the bindingReinstall so the core and binding versions match; the error names both
MAIN-CORE-0500runtimeUnknown error in a handler; no internal detail in productionRead the trace with mainsdk explain <trace_id>
MAIN-PAGE-0001runtimeA list cursor is malformed, older than 24 hours, or made by a different query, tenant or user (400)Start again without a cursor, or pass back the next value of the same query
MAIN-PAGE-0002runtimelimit is not a whole number of at least 1 (400)Pass a whole number from 1 up to the call's maximum

SECRET

CodeRaised byMeaningFix
MAIN-SECRET-0001check (build)mainsdk/secrets imported from client codeRead the secret in server code only
MAIN-SECRET-0002checkA key pattern in source codeMove the key to secrets and use secret:NAME
MAIN-SECRET-0003checkA committed .env file other than .env.exampleRemove it from git and use the secrets driver
MAIN-SECRET-0004check (build output)A value from a secret: reference is in a browser bundleKeep the call on the server; the finding names the chunk
MAIN-SECRET-0007runtimeSecrets provider unreachable; serving the last good value from memoryRestore the provider; nothing is written to disk
MAIN-SECRET-0005runtimeA secret: reference names a secret that isn't setSet it in your secrets manager, or in your shell for local development

FLAGS

CodeRaised byMeaningFix
MAIN-FLAGS-0001runtimeA flag was evaluated with no definition in config; the fallback was served, logged once per nameDefine flags.<name> in your config store, or pass the fallback you meant
MAIN-FLAGS-0002runtimeA pushed flag definition is invalid; it was refused and the last good definition keptFix the definition: enabled as a boolean, rollout from 0 to 100 with at most two decimals, one of user, in or notIn per rule
MAIN-FLAGS-0003runtimeA rule served a value of a different type from the fallback, or enabled got a non-boolean; the fallback was served, logged once per nameServe a value of the same type as the fallback

AUTH and SESSION

CodeRaised byMeaningFix
MAIN-AUTH-0001runtimeNot signed in (401 from auth.require())Sign in; the problem body carries a fix
MAIN-AUTH-0006runtimeWhatsApp code reused, expired or tried too often; the challenge is closedStart a new sign-in
MAIN-AUTH-0007runtimeOIDC SSO callback with a mismatched state or nonceRestart sign-in from your app
MAIN-AUTH-0008runtimeSAML assertion unsigned, for the wrong audience, expired or replayedCheck the IdP metadata and clock for the organisation
MAIN-AUTH-0040runtimeA sign-in challenge was verified a second time; a challenge works onceStart a new challenge with auth.challenge.start for each sign-in
MAIN-AUTH-0041runtimeInvite used, expired, revoked, or accepted by a different email (410); a mismatch leaves the invite validAsk for a new invite, or sign in with the invited email
MAIN-AUTH-0042runtimeDomain not verified, already verified by another tenant, or a public email domainPublish the TXT record the fix shows, or use a domain you own
MAIN-AUTH-0043runtimeThe change would leave the tenant with no owner (409)Make another member an owner first
MAIN-AUTH-0044runtimeThe tenant requires its SSO; this session came from another method (403)Sign in through the organisation's SSO
MAIN-AUTH-0045runtimeInvites, teams and domains are not available in a personal tenant (409)Create an organisation with auth.orgs.create
MAIN-AUTH-0046runtimeSign-in link used, expired, unknown, or opened in a browser other than the one that asked (401; the challenge is closed)Ask for a new link with links.signIn() from the same browser
MAIN-AUTH-*, MAIN-SESSION-*checkMain 27 sign-in and session rules: home-made password storage, implicit flow, long-lived tokens, tokens in local storageUse auth and its session cookies

TENANT

Planned for 0.3 (spec tenancy).

CodeRaised byMeaningFix
MAIN-TENANT-0001runtimeA tenant-scoped call ran with no tenant in context (500)Run jobs and scripts inside tenant.run(id, fn); requests get the tenant from the adapter
MAIN-TENANT-0002runtimeThe tenant doesn't exist, or the caller isn't a member or key holder (404, same body either way)Switch to a tenant you belong to
MAIN-TENANT-0003runtimeThe tenant is suspended; tenant-scoped calls fail closed (403)Resume the tenant, or list the call under tenancy.suspended.allow
MAIN-TENANT-0004runtimetenant.system() called from a file outside tenancy.system.allowMove the admin code under a listed path
MAIN-TENANT-0005runtimeA record, file, team or reference of another tenant was used; treated as not found (404)Read it inside its own tenant
MAIN-TENANT-0006runtimeThe tenant's region store or database is not configured or not reachable; nothing is written elsewhere (503)Configure the store for the tenant's region, or its entry in tenancy.databases
MAIN-TENANT-0007runtimeErasure refused: the tenant is active, under a legal hold, or still in its waiting period (409)Suspend it first, lift the hold, or wait for tenancy.erase.wait
MAIN-TENANT-0010checkA raw query on a tenant-scoped table has no tenant_id conditionUse db.<model> or add the tenant_id condition
MAIN-TENANT-0011checktenant.system() used in a file outside tenancy.system.allowMove the code or list the path
MAIN-TENANT-0012check, runtimeA per-tenant config or limit override loosens the app valueOnly tighten per tenant
MAIN-TENANT-0013checkShared isolation on a driver with row-level security, but the migrations don't enable itRegenerate the migrations with MainSDK

APIKEY

Planned for 0.3 (spec apikeys).

CodeRaised byMeaningFix
MAIN-APIKEY-0001runtimeNo key, or a malformed one: wrong prefix, wrong length, bad checksum, or a key sent in the query string (401). Decided offlineSend the key as Authorization: Bearer <key> or in the apikeys.header header
MAIN-APIKEY-0002runtimeUnknown, revoked or expired key (401). The body is the same for all three; the log says whichCreate or rotate a key
MAIN-APIKEY-0003runtimeThe key's scopes don't include the permission this action needs (403)Create a key with that scope, or call an action the key may use
MAIN-APIKEY-0004runtimeInvalid create or rotate input: a scope not under apikeys.scopes, an expiry in the past or past max-ttl, an overlap over 30 days, or an empty name (400)Fix the input the error names
MAIN-APIKEY-0005runtimeThe caller may not issue this key: no apikeys.manage permission, a scope the caller doesn't hold, or a tenant other than the current one (403)Ask for the permission, or issue only scopes you hold in the current tenant
MAIN-APIKEY-0006runtimeThe key's rate limit is reached (429, with Retry-After)Wait for Retry-After, or raise the rate with a new key
MAIN-APIKEY-0007runtimeThe key's environment doesn't match: a test key in env: prod, or a live key anywhere else (401). Decided offlineUse a key made for this environment
MAIN-APIKEY-0008runtimeThe key store can't be reached. Keys verified in the last 15 minutes are served from memory and this is logged once; other keys get 503 (retryable)Restore the store; retry the call
MAIN-APIKEY-0009runtimerotate on a revoked or expired key (409)Create a new key instead
MAIN-APIKEY-0010checkA key in this app's format, with a valid checksum, is committed to sourceRemove it, revoke the key and issue a new one
MAIN-APIKEY-0011checkA scope under apikeys.scopes that no access permission definesDefine the permission in access, or remove the scope

PLAN

Planned for 0.3 (spec entitlements).

CodeRaised byMeaningFix
MAIN-PLAN-0001runtimeThe tenant's plan doesn't include this feature (403, with an upgrade hint naming the plans that do)Upgrade the plan, or grant the feature with entitlements.grant
MAIN-PLAN-0002runtimeThe tenant has reached this limit of its plan (403, with an upgrade hint)Upgrade the plan, or raise the limit with entitlements.grant
MAIN-PLAN-0003runtimeAn override would remove a feature or lower a limit; overrides may only add (400)Change the plan in main.yaml instead
MAIN-PLAN-0004runtimeThe plan store can't be reached; the last known plan is served, or the default plan for a tenant with none. Logged once per outageRestore the store; nothing else to do
MAIN-PLAN-0005runtimeA subscription event names a price under no plan, or carries no tenant; it is ignored and the plan is unchangedAdd the price to a plan under plans.<name>.prices, or tag the subscription with its tenant
MAIN-PLAN-0006check, runtimeplans or entitlements is invalid: the default plan isn't defined, a name is both a feature and a limit, a limit has a bad value, a windowed usage source has a limit with no window, or a price is under two plans. The app doesn't startFix the key the error names
MAIN-PLAN-0007runtimeA plan change for another tenant outside tenant.system(), or by a caller without the entitlements.manage permission (403)Make the change inside tenant.system() in admin code, or grant the permission
MAIN-PLAN-0008runtimeA feature or limit name that no plan declares. has returns false and logs once; limit and within throw (500)Declare the name under plans
MAIN-PLAN-0009runtimeThe tenant has reached its plan's request rate (429, with Retry-After)Wait for Retry-After, or move to a plan with a higher requests limit
MAIN-PLAN-0010checkA feature or limit name used in code that no plan declaresDeclare the name under plans, or fix the typo

ACCESS and POLICY

CodeRaised byMeaningFix
MAIN-ACCESS-0001runtimeAccess denied (403)Check the role or relation the action needs
MAIN-ACCESS-0004checkRelations need a ReBAC driver (openfga, spicedb, permit) or Cedar entitiesSwitch access.driver or model the relation in Cedar
MAIN-ACCESS-0007runtimeRemote engine unreachable and no cached decision; denied (fail closed)Restore the engine; tune access.unreachable.cache
MAIN-ACCESS-0011checkOpenFGA 1.8.0 to 1.13.1 pinned (CVE-2026-34972, wrongly permissive BatchCheck)Upgrade OpenFGA past 1.13.1
MAIN-ACCESS-0020runtimeAn attribute source timed out or is down, so access denied the requestWait for the source or fix its driver; never turn the gate off
MAIN-POLICY-0004runtime (load)A repo policy weakens an org policy; loading fails, naming both filesRemove the repo policy or change it at the org layer
MAIN-POLICY-0009runtimeA new policy set failed to load; the previous version stays in forceFix the syntax; run mainsdk test policy
MAIN-POLICY-0011runtime (load)A Cedar policy uses a construct the built-in TypeScript engine doesn't support yet; it names the construct and line and never ignores itRewrite the policy without the construct, or use the OPA driver

DATA, KEYS and PRIV

CodeRaised byMeaningFix
MAIN-DATA-0001checkRaw database client used outside MainSDKWrap it: withPrisma(client) or withDrizzle(db)
MAIN-DATA-0007runtimeRecord belongs to another user (403)Scope the query with db.<model>.for(user)
MAIN-DATA-0013checkA query joins tables across regionsQuery each region separately; combine only totals
MAIN-DATA-0020checkA field labelled pan: card numbers are never storedUse hosted checkout through pay; drop the field
MAIN-DATA-0021checkA field that holds personal data has no labelAdd a label: personal, sensitive, child or phi
MAIN-DATA-0030checkSQLite local driver in productionSet db.driver to postgres, neon or supabase for prod
MAIN-DATA-0008runtimeThe record isn't there, with tenancy off (404)Check the id and the model
MAIN-DATA-0009runtimeA create repeats an id or a declared unique value (409)Leave id out, or change the unique value
MAIN-DATA-0031runtimeThe local SQLite driver can't start: this Node has no node:sqlite (500)Use Node 22.18 or later, or the postgres driver
MAIN-DATA-0032runtimedb.driver is not built, or a Postgres driver has no client (400)Use sqlite, postgres, neon or supabase, and pass the postgres option
MAIN-DATA-0050runtimeA query ran past its statement timeout and was cancelled (503, not retried)Add an index or narrow the query; raise db.timeout.request up to 30s, or use a job
MAIN-DATA-0052runtimeNo connection was free within db.pool.acquire (503 with Retry-After: 1)Retry; raise db.pool.max or shorten transactions
MAIN-DATA-0053runtimeA query took longer than db.slow (warn log, once a minute per query shape)Add an index or narrow the query
MAIN-DATA-0054runtimeOne query shape ran more than db.repeat times in one request or job (warn log)Load them with one where: { id: { in: ids } } query
MAIN-DATA-0060runtimeifVersion doesn't match the record's version (409; 412 from If-Match)Read the record again and retry
MAIN-DATA-0063runtimerestore of a record not in trash, or past its trash period (404)Restore within the trash period
MAIN-DATA-0066runtimeA write to a versioned record came with no If-Match (428)Send the ETag you read, or If-Match: *
MAIN-DATA-*, MAIN-API-*checkMain 27 database and API rules: SQL built from strings, shared admin credentials, unvalidated input, open CORSUse typed queries through db; follow the fix in each finding
MAIN-KV-0001runtimeincr was given a step that is not a whole number (400), or the key holds a value that is not a whole number (409)Pass an integer by; use incr only on keys it created
MAIN-KV-0002runtimettl is not a positive duration (400)Pass milliseconds or a duration such as 30s
MAIN-KV-0003runtimeA key is empty or longer than 512 characters (400)Use a shorter, non-empty key
MAIN-KEYS-0001checkLocal keys driver in productionSet keys.driver to a KMS driver for prod
MAIN-KEYS-0004runtimeData can't be decrypted because its owner's key was destroyed (erasure)Expected after privacy.erase with keys.per-user: true

NET

CodeRaised byMeaningFix
MAIN-NET-0001checkRaw socket, another HTTP client or direct fetch outside the SDK: new WebSocket, EventSource, node:http, node:https, node:dgram, ws, or git, curl or wget run as a child processCall through http.* or a driver; for a program, declare it under permissions.processes and run it with system.run
MAIN-NET-0002check, runtimeCall to a host not in network.allow (or not declared by a driver)Add the host to network.allow, or remove the call
MAIN-NET-0003runtimeRedirect to an undeclared host refusedDeclare the target host or call it directly
MAIN-NET-0004checkA third-party API offers less than TLS 1.2 (TLS 1.3 is the minimum for endpoints your app serves, under MAIN-NET-*)Ask the provider to upgrade; meanwhile an exception with an expiry
MAIN-NET-0005runtimeAn entry in network.allow is not an IP, a CIDR range, an exact host or a *.domain (for example a prefix length out of range)Fix the entry; the error names it
MAIN-NET-0006runtimeA request was redirected more times than the SDK follows, or redirect: "error" met a redirectCall the final URL directly, or fix the redirect loop
MAIN-NET-0007checkThe code connects to a host that network.allow doesn't list; the finding names the call (http, websocket, event-stream, database, git)Add the host to network.allow, or remove the call; npx mainsdk discover prints the lines to add
MAIN-NET-0008runtimehttp.json or http.events got a non-2xx answer (429 when the provider rate-limits, else 502), or JSON that didn't parse; the body is never echoedCheck the URL, the credentials and the service status, or read the response with http.fetch
MAIN-NET-0009runtimeAn outbound call timed out: the connect or total timeout of its last attempt, or its deadline, passed (504; the error names which)Raise the timeout for that host or call, or check the provider's latency
MAIN-NET-0010runtimeThe circuit breaker for the host is open, or half-open with its probe in flight; no request was sent (503, retryable, retryAfter is the rest of the cooldown)Wait for retryAfter, and check the provider's status; breakers are per app instance
MAIN-NET-0011runtimeAn outbound call failed with a network error (refused, reset, DNS failure) on its last attempt (502; states the number of attempts)Check the host, DNS and the provider's status
MAIN-NET-0012runtimeA value under network.http is invalid: a bad duration, attempts outside 1 to 10, failures outside 1 to 100 %, min below 1, or an unknown key (fails at load; names the key)Fix the value the error names
MAIN-NET-*checkMain 27 network rules: plain HTTP, TLS below 1.3 on public endpointsServe over TLS 1.3

PERM

Permission codes cover the server's own disk, operating system facts and programs (spec app-permissions). They appear only for what permissions in main.yaml declares; see Declare what your app uses.

CodeRaised byMeaningFix
MAIN-PERM-0001checkRaw node:fs, node:os or node:child_process used outside a driverUse disk for files and system for facts and programs
MAIN-PERM-0002runtimeIn enforce mode, a disk path, a system fact or a program is used but not declared under permissions (403)Declare it under permissions in main.yaml, or remove the code that asks
MAIN-PERM-0003checkA disk path, a system fact or a program found in the code isn't declared under permissionsDeclare it; npx mainsdk discover prints the lines to add
MAIN-PERM-0004runtimeAn unknown name under permissions.systemUse one of user, hostname, platform or network-interfaces
MAIN-PERM-0005runtimeA declared program could not start, for example because it is not installed on the serverInstall it on the server, or check its name

AI, MCP and actions

CodeRaised byMeaningFix
MAIN-AI-0001checkThe driver's training setting is weaker than ai.data.trainingPick a driver or plan that meets it
MAIN-AI-0005runtimePrompt injection suspected in a tool result; wrapped as untrusted dataReview the source of the tool result
MAIN-AI-0007runtimeCall refused: it would pass a spend limitRaise ai.limits or wait for the period to reset
MAIN-AI-0010runtime (start)ai.tool() for a function not declared with action()Declare it with action()
MAIN-AI-0011runtimeTyped output does not match schema after its repairs (one by default, up to two with repairs); no value is returnedFix the schema or the prompt; never use the raw reply as if it were valid
MAIN-AI-0002runtimeThe model isn't in the ai.models allowlist (403)Add it to ai.models, or call an allowed model
MAIN-AI-0003runtimeThe model provider answered with an error (502); the message has the status, never the bodyCheck the key, the model name and the provider's status, then retry
MAIN-AI-0004runtimeNo price is set for the model, so its spend can't be limitedAdd the model to ai.prices
MAIN-AI-0006runtimeThe driver has no embeddings, for example anthropicUse a driver with embeddings, such as openai
MAIN-AI-0008runtimeAn agent's model call waits for a person's approval; nothing reached the provider (202)A person approves it, then the call runs
MAIN-AI-0012runtimeA call passed neither or both of prompt and messages (400)Pass prompt for one instruction, or messages for a conversation
MAIN-AI-0013runtimeai.driver names a driver that isn't built yetUse fake, anthropic or openai until it ships
MAIN-AI-0014runtimeA model verb option is invalid: repairs is not 0, 1 or 2, a label list is empty or repeats a label, or a summary length is unknown (400); no request is sentPass a valid option, as the verb's page lists them
MAIN-AI-0015runtimeA speech or transcription option is invalid: both or neither of text and input, an unknown format or sample rate, or empty text (400); nothing is sentPass one of text or input and a listed format
MAIN-AI-0016runtimeVoice clone refused: no granted voice-clone consent recorded by the owner in their own session (403)The voice's owner records the consent themselves, then clones
MAIN-AI-0017runtimeThe consent statement's transcript doesn't match ai.speech.clone.script, or the statement and samples aren't one speaker (422)The owner reads the script aloud again
MAIN-AI-0018runtimeThe voice can't be used: blocked or deleted after consent was revoked or the owner erased, or the caller isn't its owner or in its shared tenant (403)Use another voice; only the owner can clone it again
MAIN-AI-0019check, runtimeA voice that isn't an alias under ai.speech.voices or a cloned voice idAdd an alias under ai.speech.voices, or use a cloned voice id
MAIN-AI-0020runtimeSpeech text holds labelled data and the speech driver's data use doesn't meet ai.data (403); nothing is sentUse a driver declared with zero retention, or leave the data out
MAIN-AI-0021runtimeThe driver doesn't offer this: speech, transcription, streaming, diarisation or cloning (501)Pick a driver that offers it, as its page lists
MAIN-AI-0022runtimeDeleting a cloned voice at the provider failed; the voice stays blocked and the delete is retried (logged)Nothing to do; check the provider's status if it keeps failing
MAIN-AI-0023runtimeAudio is larger than ai.speech.max-audio, or a live transcription passed max-duration (413)Send shorter audio, or raise the limit on purpose
MAIN-MCP-0001runtimeThe server is not in mcp.servers; no request leaves the processAdd the server to main.yaml on purpose, and allow its host under network
MAIN-MCP-0002runtimeA pinned server's tool description changedRead the diff in mainsdk check; a person accepts the new description
MAIN-MCP-0003runtimeA tool description changed after signing; the tool is left outRe-sign by releasing again; investigate the change
MAIN-MCP-0004runtimeA call limit was reached, for example per-user: 100/day; the call is refused before any requestWait for the period to reset, or raise limits on purpose
MAIN-MCP-0005runtimeA write or destructive tool call wasn't confirmed by the person, so nothing ran (returned in the tool result)Wire elicit so the person can accept, or have them accept
MAIN-MCP-0006runtimeThe MCP server answered with an error or not at all (502)Check the server and the tool arguments
MAIN-MCP-0007runtimeA remote server's protected resource metadata is missing or invalid, or its resource isn't the server's URL (502)Fix the server's protected resource metadata, or ask its owner to
MAIN-MCP-0008runtimeThe remote server's authorization server offers no dynamic registration and no client-id is set for it (500)Set client-id for the server under mcp.servers
MAIN-MCP-0009runtimeA token sent to the app's MCP server was issued for another resource (401); it is never passed onSend a token issued for this app's MCP server
MAIN-MCP-0010runtimeA token sent to the app's MCP server lacks the scope the tool needs (403, insufficient_scope)Ask the person to connect again with the scope the tool needs
MAIN-ACTION-0001runtimeAn action's input failed its schema (400)Send input that matches the action's schema

SCHEMA and parse

CodeRaised byMeaningFix
MAIN-SCHEMA-0001runtimeA value does not match its schema (422); the problem's errors lists each issue's path, code and message, never the valueSend a value that matches the schema; read each errors entry
MAIN-SCHEMA-0002runtimeThe input is longer than the parser's size limit (413); nothing was matchedSend a shorter input, or raise maxLength on purpose
MAIN-SCHEMA-0003runtime (definition)A pattern has a nested quantifier, such as (a+)+, and is refused when the schema or parser is defined (500)Rewrite the pattern so no repeated group sits inside another repeat
MAIN-SCHEMA-0004runtimeA parser found no match, or no parser in parse.first matched (422); the input is not echoedCheck the input's format, or add a parser or a model fallback to parse.first

AGENT

CodeRaised byMeaningFix
MAIN-AGENT-0001runtimeA call names an agent that is not under agentsFix the name, or add the agent under agents
MAIN-AGENT-0002runtimeThe agent is over its budget; the call is refused and nothing reaches the providerWait for the budget period to reset, or raise the budget on purpose
MAIN-AGENT-0003runtimeAn agent tried to approve its own stepA person approves; an agent never can
MAIN-AGENT-0004runtimeThe agent is switched off (enabled: false)Set enabled: true when a person decides to
MAIN-AGENT-0005runtimeAn approval id that isn't pending: unknown, already approved or expiredList pending approvals and use one of their ids
MAIN-AGENT-0006runtimeThe store that counts budgets did not answer, and the agent has a budget, so the call is refused (503, retryable)Check runtime.store; calls with no budget keep running
MAIN-AGENT-0007runtimeA sync budget call (admit, charge, request) on a store other instances shareUse reserve, settle, release or ask

Messaging, payments, files, webhooks and events

CodeRaised byMeaningFix
MAIN-EMAIL-0001checkMarketing email without an unsubscribe link (the rule behind the email.unsubscribe guarantee)Send marketing with email.marketing({ …, unsubscribe })
MAIN-NOTIFY-0003runtimeSMS skipped: no recorded opt-inRecord SMS consent first
MAIN-NOTIFY-0004runtimeWhatsApp skipped: no consentRecord WhatsApp consent first
MAIN-PAY-0001checkA form posts card data to an app routeUse hosted checkout: pay.checkout()
MAIN-PAY-0030runtimepay.agent named a payee not in pay.payees, or an amount above the payee's maxDeclare the payee with its host and max, and allow the host under network
MAIN-PAY-0002runtimeAn amount isn't positive money, or doesn't fit the currency's minor units (400)Pass money such as "$20.00", or a positive integer in minor units
MAIN-PAY-0010runtimeA payment webhook failed verification: bad or missing signature, or outside the 5-minute window (400); no handler ranCheck the webhook secret, and pass the raw, unparsed body
MAIN-PAY-0020runtimeThe payment provider answered with an errorLook up the request in the provider's dashboard logs
MAIN-PAY-0031runtimepay.agent was called with no agent payment rail setPass agentRail when you create the app; MainSDK holds no keys or funds
MAIN-PAY-0032runtimeA held agent payment was sent before a person approved itA person approves it first
MAIN-FILES-0002runtimeaccess denied this user a file URL (403), or someone other than the uploader called files.complete()Read or complete as the owner, or add an access rule for the reader
MAIN-FILES-0005runtimefiles.complete() ran the scan and found an infected file; the upload fails and the file is quarantined, with no readable URLNothing to fix in code; ask the user for a clean file
MAIN-FILES-0010checkA storage SDK used for user uploads outside a files driver, for example @vercel/blob in route codeUpload through files, and pick the store with files.driver
MAIN-FILES-0003runtimeA per-call maxSize is above files.maxSizeLower it in the call, or raise files.maxSize on purpose
MAIN-FILES-0004runtimeAn upload target is invalid, already used or older than 15 minutes (403)Ask the server for a new one with files.uploadUrl()
MAIN-FILES-0006runtimeThe file is larger than the upload allows (413); it is removed and never readableSend a smaller file
MAIN-FILES-0007runtimeThe file's type isn't one the upload allows (415); it is removed and never readableSend one of the allowed types
MAIN-FILES-0008runtimefiles.complete() ran before any bytes reached the store (409)Send the file to upload.url first
MAIN-FILES-0011runtimeThe s3 driver found no credentials: no keys in main.yaml and no runtime roleSet files.accessKeyId and files.key: secret:NAME, or run with an IAM role
MAIN-FILES-0012runtimefiles.upload() from the server isn't supported by the s3 driver yetUse files.uploadUrl() and let the browser send the file
MAIN-FILES-0013runtimeThe store answered with an error (502)Check the bucket, region and credentials; the message has the store's status
MAIN-FILES-0014runtimefiles.driver names a driver that isn't built yetUse local, memory or s3 until it ships
MAIN-FILES-0015runtimeThe getqr.id API has no endpoint for this step, such as downloading or deleting stored bytes (501)Send files with files.uploadUrl() and read them with files.url(); getqr.id scans on its side
MAIN-SHARE-0001checkA link shortener, deep-link or QR code library imported in app code, such as bitly, tinyurl, qrcode, qrcode.react, react-qr-code, qr-code-styling, branch-sdk or @react-native-firebase/dynamic-linksShare through share() or links and getqr.id (ADR-0009, ADR-0056)
MAIN-SHARE-0002runtimeexpiresIn is longer than share.max-expiry (400)Use a shorter expiresIn, or raise max-expiry on purpose
MAIN-SHARE-0003runtimeA share asked for access other than read (400); share links never grant writesUse access: "read"
MAIN-SHARE-0004runtimeshare.stats() was called without the person's consent (403)Ask for analytics consent, then pass consent: true
MAIN-SHARE-0005runtimegetqr.id answered a share or stats call with an errorCheck the key, its scopes and the plan; quote the request id to support
MAIN-SHARE-0006runtimegetqr.id returned a share that breaks the rules (kept forever, no expiry, or off getqr.id); it is revoked and the call fails (502)Check the plan and the key
MAIN-SHARE-0007checkCode calls, or network.allow lists, a link shortener, deep-link or QR rendering service such as api-ssl.bitly.com, tinyurl.com, is.gd, api.short.io, firebasedynamiclinks.googleapis.com, api2.branch.io or api.qrserver.comRemove the call and the network.allow entry; share through share() (ADR-0056)
MAIN-SHARE-0008runtimeshare.driver: local in production; the app refuses to start (500)Set share.driver: getqr and share.key in main.env.prod.yaml
MAIN-SHARE-0009runtimeA local share link was opened after it expired or was revoked (410)Make a new share
MAIN-SHARE-0010runtimeshare.update was asked to keep a share forever (400); share links always expire, and placements are the only kept linksUse extend within max-expiry, or a placement for a printed QR code
MAIN-SHARE-0011runtimeshare.placements.create failed its row checks and created nothing (422; the problem lists each row, field and reason)Fix the listed rows and send all of them again with the same idempotency key
MAIN-SHARE-0012runtimeA getqr.id webhook event type that isn't in the pinned contract; acknowledged, logged once per type, not passed onTake the new getqr.id contract version with contract diff --vendor getqr
MAIN-SHARE-0013runtimeA share's title or metadata holds personal data, metadata has more than 16 keys or a reserved mainsdk_ key, or a contact share isn't the signed-in person's own (400)Use record ids your app resolves after sign-in; share only the person's own contact card
MAIN-HOOK-0002runtimeIncoming webhook with a wrong signature or a timestamp too old (400)Check the signing secret and the sender's clock
MAIN-HOOK-0003check, runtimewebhooks.receive names neither a key under webhooks.inbound nor a preset, or an entry names an unknown presetDeclare the endpoint under webhooks.inbound with a listed preset
MAIN-HOOK-0004runtimeA customer endpoint URL is refused: not https, carries credentials, or is or resolves to a loopback, private, link-local, shared, multicast or metadata address (400; a delivery fails without connecting)Use a public https URL with no credentials
MAIN-HOOK-0005runtimeThe tenant already has webhooks.endpoints.max-per-tenant endpoints (409)Delete an endpoint, or raise the limit on purpose
MAIN-HOOK-0006runtimeAn event type that isn't under webhooks.endpoints.events (400)Subscribe to a listed type, or add it to main.yaml
MAIN-HOOK-0007runtimeAn endpoint was disabled after disable-after failures; an audit event and webhook.endpoint.disabled are writtenFix the receiver, then enable the endpoint again
MAIN-HOOK-0008runtimeA test or redeliver to a disabled endpoint (409)Enable the endpoint first
MAIN-HOOK-0009runtimeNo endpoint or delivery with that id in the current tenant (404)Use an id from webhooks.endpoints.list
MAIN-HOOK-0010runtimeAn endpoints call without the webhooks.manage permission (403)Grant webhooks.manage to the person who manages endpoints
MAIN-HOOK-0011checkA twilio inbound entry has no public-urlSet public-url to the URL Twilio calls
MAIN-HOOK-0012CLImainsdk webhooks replay refused: not a dev environment, no mainsdk dev running, or an unknown id (exit 2)Run mainsdk dev, then pick an id from mainsdk webhooks list
MAIN-EVENT-0004checkA breaking event schema change under the same versionPublish the change as a new event version
MAIN-EVENT-0010check, runtimeA broadcast payload is larger than max-payload (runtime), or max-payload is over 1MB (check)Send less data, or lower max-payload to 1MB or less; use events.publish or jobs for large messages
MAIN-EVENT-0011check, runtimeevents.broadcast uses the local driver in production, so other instances never receive itSet events.broadcast.driver: redis in main.env.prod.yaml
MAIN-EVENT-0012runtimeA broadcast topic doesn't match ^[a-z0-9][a-z0-9._-]{0,127}$, or the payload isn't JSONUse a lowercase topic such as cache.invalidate, and send JSON
MAIN-EVENT-0013runtimeA broadcast was dropped because the driver is unreachable; the call resolves with dropped: true and logs once per outageRestore the driver. Broadcast is best effort, so anything that must happen goes through events.publish or jobs

LOG, TUF and the Main mark

CodeRaised byMeaningFix
MAIN-LOG-0003runtimeMAINSDK_DEBUG=driver ignored in productionUse a debug session (phase 2)
MAIN-LOG-0005runtimeAn attribute not in telemetry@1 was dropped before exportRemove the attribute or propose it for the contract
MAIN-LOG-0010runtimeAudit sink unavailable; buffering to local diskRestore the sink
MAIN-OBS-0001runtimeAn observer threw or rejected; caught, the request is untouched, and the observer keeps receivingFix the observer; it is logged at most once a minute
MAIN-OBS-0002runtimeAn observer's queue was full and its oldest events were droppedMake the observer faster, or raise its max
MAIN-OBS-0003runtimeAn observer's synchronous work took over 10 ms and blocked the event loopMove the work into an async step or a job
MAIN-OBS-0004runtime (testing kit)A published payload breaks its channel schemaMatch the payload to the channel's schema, or add a new channel version
MAIN-OBS-0005runtimeobserve() named a channel that isn't in the registry, or a pattern that matches noneUse the channel the message suggests; see observe.channels()
MAIN-TUF-0001runtimeRollback: the mirror served older metadata; the newer version is keptNone in your app; report the mirror
MAIN-TUF-0004runtimeDelivered packs are stale; the last good pack stays in forceNone needed; it refreshes when the mirror is back
MAIN-INFO-0002CLIThe signed /.well-known/mainsdk.json doesn't verify (exit 1)Treat the record as untrusted
MAIN-CRYPTO-0002checkA Main 27 crypto rule, in the family that refuses MD5, SHA-1 and DESUse crypto or keys
MAIN-LOG-*, MAIN-CRYPTO-*checkMain 27 logging and crypto rules: secrets or personal data in logs, MD5, SHA-1, DESFollow the fix in each finding
MAIN-SUPPLY-*, MAIN-RELEASE-*checkMain 27 supply-chain rules: unpinned or unverified packages, unsigned buildsFollow the fix in each finding

ANALYTICS

Planned for 0.3 (spec analytics).

CodeRaised byMeaningFix
MAIN-ANALYTICS-0001runtimeA product event that analytics.events doesn't declare (throws in dev and test; dropped and logged once per name in production)Declare the event under analytics.events
MAIN-ANALYTICS-0002runtimeAn event's props fail its schema (throws 422 with issue paths in dev and test; dropped and logged once per name in production)Send props that match the declared types
MAIN-ANALYTICS-0003runtimeAn event was dropped: no consent for its purpose. Logged as a count, never with the personCollect consent for the event's purpose
MAIN-ANALYTICS-0004runtimeA query names an undeclared event, prop or metric, or a by the query kind doesn't take (400)Declare the name, or use a by the query kind takes
MAIN-ANALYTICS-0005runtimeA metric attribute that isn't declared was dropped, or a metric passed 1,000 attribute combinations and the rest were folded into _otherDeclare the attribute, or use fewer distinct values
MAIN-ANALYTICS-0006runtimeA driver in analytics.to is unreachable; events were buffered, then dropped with a counterRestore the driver; nothing else to do
MAIN-ANALYTICS-0007runtimeanalytics.query called without builtin in analytics.to (501)Add builtin to analytics.to
MAIN-ANALYTICS-0008runtimeThe event's region store isn't configured or reachable; the event was dropped and written nowhere elseConfigure the store for the tenant's region
MAIN-ANALYTICS-0010checkanalytics.track or page with an event name that isn't declared, or isn't a string literalDeclare the event and pass its name as a string literal
MAIN-ANALYTICS-0011checkA prop or metric attribute that would identify a person: a name such as email, phone, name, ip, userId, deviceId, idfa, gaid or fingerprint, or a field with a data labelRemove the identifying prop; use a declared, non-identifying one
MAIN-ANALYTICS-0012checkA driver in analytics.to doesn't serve a region the app stores data in, or declares cross-app identifiers or third-party cookiesPick a driver that serves your regions without cross-app identifiers
MAIN-ANALYTICS-0013checkA children's audience (users.audience: children) with a per-person driver (posthog) in analytics.toUse builtin or otel for a children's audience

HEALTH

Spec health.

CodeRaised byMeaningFix
MAIN-HEALTH-0001runtimeThis instance is not ready: starting, draining, or a critical dependency is down (503 on /readyz)Wait for start-up, or restore the dependency
MAIN-HEALTH-0002runtimeA request arrived after the app stopped accepting work (503 with Retry-After and Connection: close)Retry; the load balancer should stop sending traffic once /readyz fails
MAIN-HEALTH-0003runtimeThe shutdown deadline cut work that was still running; the record lists what was releasedRaise health.deadline, or shorten the work
MAIN-HEALTH-0004runtimeA probe threw or timed out; its dependency is marked down (logged once per change)Fix the dependency or the probe
MAIN-HEALTH-0005checkAn slo value is invalid: availability outside 90% to 99.999%, or a latency that isn't a durationUse a percentage in range and a duration such as 300ms
MAIN-HEALTH-0006checkhealth.critical names a dependency the app doesn't configure, or names mainsdk-cloud or tuf; or drain-delay plus 2s is not less than deadlineList only dependencies the app configures; raise deadline or lower drain-delay
MAIN-HEALTH-0010runtimeThe availability error budget is burning faster than a burn rule allowsFind the failing dependency or release
MAIN-HEALTH-0011runtimeThe latency budget is burning faster than a burn rule allowsFind the slow call or release

ALERT

Spec alerts.

CodeRaised byMeaningFix
MAIN-ALERT-0001checkAn alerts value is invalid: an unknown driver, source or severity, a route to an undeclared recipient, a quiet-hours time or time zone that doesn't parse, or an escalation after shorter than group.waitDeclare every recipient a route names, use a known driver and an IANA time zone, and escalate after the group wait
MAIN-ALERT-0002checkProduction has an alerts section, but no route sends critical alerts to a recipientAdd a route for severity: critical, or a default route with no match
MAIN-ALERT-0003checkA webhook recipient's host isn't in network.allow, or a recipient key or webhook URL is written as a literalAdd the host to network.allow and reference keys and URLs as secret:NAME
MAIN-ALERT-0010runtimeAn alert was raised or resolved; the log record carries the alertNothing to fix; follow the alert's runbook
MAIN-ALERT-0011runtimeA recipient failed after its last retry; the others were still sent toCheck the recipient's key or URL with mainsdk alerts test <recipient>
MAIN-ALERT-0012runtimeThe runtime store didn't answer; dedupe and escalation fell back to this instanceRestore the store; until then each instance may send once
MAIN-ALERT-0013runtimealerts.raise refused or trimmed an input: a key over 200 characters, more than 20 attrs, or an attr outside telemetry@1Shorten the key and send only telemetry@1 attributes
MAIN-ALERT-0014runtimealerts.ack refused: the caller lacks alerts.manage (403)Grant alerts.manage to the people who acknowledge alerts
MAIN-ALERT-0015runtimeA recipient passed max-per-hour; the rest of the hour arrives as one summaryGroup more alerts, fix the noisy source, or raise max-per-hour

RESOURCE

Spec resources.

CodeRaised byMeaningFix
MAIN-RESOURCE-0001runtimeA new non-critical request or realtime connection was shed (503 with Retry-After); logged at most once a minute with a countRetry after the delay; add capacity, or list the route under resources.critical if it must never be shed
MAIN-RESOURCE-0002runtimeThe instance entered or left pressure or shed, with the reasons and the valuesFind what uses the CPU, event loop or memory; mainsdk status shows the snapshot
MAIN-RESOURCE-0003checkA resources value is invalid: a percentage outside 10% to 100%, a loop under 20ms, a shed threshold not above its pressure threshold, a critical pattern that doesn't parse, or nice outside 0 to 19Use values in range and a shed threshold above pressure
MAIN-RESOURCE-0004runtimenice couldn't be applied; the app starts anyway (logged once)Remove nice, or run where the process may lower its own priority
MAIN-RESOURCE-0005runtimeBackground work waited longer than max-pause; it now runs one at a time until pressure endsAdd capacity, or move the background work to a worker process
MAIN-RESOURCE-0006runtimeThe V8 heap limit is above the container's memory limit, so the process can be killed before the heap fillsSet --max-old-space-size to the value the record names

SEAL

Spec seal.

CodeRaised byMeaningFix
MAIN-SEAL-0001runtimeThe files on disk don't match the sealed build hash (logged in warn mode; the app refuses to start in refuse mode)Redeploy the sealed build
MAIN-SEAL-0002runtimeNo seal, or an unreadable one, in an environment other than dev while seal.mode isn't offRun the seal step in the build
MAIN-SEAL-0003sealThe record would carry a secret value, an env value or personal data; nothing is writtenRemove the value from what is sealed
MAIN-SEAL-0004verifyThe signature is valid but the signer isn't one of seal.signers or the given --key or --identityVerify with the expected signer, or add it to seal.signers
MAIN-SEAL-0005sealA file can't go into the build hash: a symlink leaving the roots, an unreadable file, a path with CR or LF, or a missing rootFix or exclude the file the error names
MAIN-SEAL-0006checkcheck --env prod with seal.mode: offTurn sealing on for production
MAIN-SEAL-0007verifyThe record's build hash doesn't match the files of the folder given to seal verifyVerify the folder that was sealed
MAIN-SEAL-0008seal diffA sensitive capability is new since the old seal: a call of a new sensitive kind, a new sensitive call, a widened grant, or a new destructive actionReview the change; a person accepts it

REALTIME

Spec realtime.

CodeRaised byMeaningFix
MAIN-REALTIME-0001runtimeSubscribe with no session (401)Sign the person in first
MAIN-REALTIME-0002runtimeSubscribe refused: access denied, or a user: channel that isn't the caller's (403)Subscribe to a channel the person may read
MAIN-REALTIME-0003runtime, checkA channel prefix not declared under realtime.channels (404 on subscribe, a throw on publish; a check on a literal in code)Declare the prefix under realtime.channels
MAIN-REALTIME-0004runtimeEvent data is not JSON, or is larger than max-eventSend JSON under the size limit
MAIN-REALTIME-0005runtimeA channel or event name doesn't match its patternUse the pattern the error shows
MAIN-REALTIME-0006check, runtimeThe local driver in production without single-instance: trueUse a shared driver, or set single-instance: true for one instance
MAIN-REALTIME-0007checkmax-event plus the 4KB envelope is larger than events.broadcast.max-payloadLower max-event, or raise events.broadcast.max-payload
MAIN-REALTIME-0008runtimeA stream was closed because its reader fell more than buffer behind (logged)Reconnect; read faster or raise buffer
MAIN-REALTIME-0009runtimeThe person already has per-user open streams (429)Close another stream, or raise per-user
MAIN-REALTIME-0010runtimeWebSocket upgrade refused: the Origin is neither the app's own nor in inbound.cors.origins (403)Add the origin to inbound.cors.origins
MAIN-REALTIME-0011runtimeWebSocket upgrade refused: the ticket is unknown, expired, used or from another tenant (401)Get a fresh ticket with realtime.ticket() right before connecting
MAIN-REALTIME-0012runtime, checkA client message or stream refused: no send action on the prefix, access denied, or no handlerDeclare send under realtime.channels.<prefix> and register realtime.on
MAIN-REALTIME-0013runtimeA client message isn't JSON, has an unknown type, is over max-message or fails the handler's schemaSend JSON that matches the handler's schema
MAIN-REALTIME-0014runtimeClient messages over realtime.socket.rateSend less often, or raise the rate on purpose
MAIN-REALTIME-0015checkrealtime.transports lists websocket on an adapter or platform without HTTP upgradeUse sse, or a server adapter with upgrade support
MAIN-REALTIME-0016runtime, checkA binary stream refused: prefix not under realtime.streams, type not listed, or max-per-socket reachedDeclare the prefix and type under realtime.streams
MAIN-REALTIME-0017runtimeA stream passed its byte budget, or a frame passed max-frame; the stream or socket is closedSend smaller frames, or raise the budget on purpose

WORKFLOW

Spec workflows.

CodeRaised byMeaningFix
MAIN-WORKFLOW-0001runtimestep, sleep, waitFor or approve called outside a workflow run (500)Call it inside a workflow function
MAIN-WORKFLOW-0002runtimeOn resume, the code reached a step the journal doesn't have in that place (code changed under a live version); the run stops as stuckShip the change as a new workflow version
MAIN-WORKFLOW-0003runtimeNo registered code for the run's workflow version; the run stops as stuckRegister the version the run started on
MAIN-WORKFLOW-0004runtimeA step result or workflow input is not JSON, or is larger than max-step-resultReturn JSON under the size limit
MAIN-WORKFLOW-0005runtimeA step failed after its last retry; the run is failedFix the cause and start a new run
MAIN-WORKFLOW-0006runtimeNo run with that id in the current tenant (404)Use an id from this tenant
MAIN-WORKFLOW-0007runtimeThe journal store is unreachable, so the run was not started (503, retryable)Retry once the store is back
MAIN-WORKFLOW-0008runtimeCancel of a run that has already finished (409)None; the run is done
MAIN-WORKFLOW-0009runtime, checkA duration is not a valid <n><s|m|h|d> value, or is over 365dWrite a duration such as 30m
MAIN-WORKFLOW-0010checkA clock, random or network call (Date.now, new Date(), Math.random, crypto.randomUUID, http.*, fetch) in a workflow function outside a stepMove the call into a step
MAIN-WORKFLOW-0011check, runtimeThe local driver in productionUse a database driver in main.env.prod.yaml
MAIN-WORKFLOW-0012checkTwo workflow definitions with the same name and versionGive each definition its own name and version

APPS

Spec app-registry.

CodeRaised byMeaningFix
MAIN-APPS-0001runtimeThe registry folder is unsafe (world-writable, or owned by another user and not root) or not writable; nothing is written and the app keeps servingFix the folder's owner and mode
MAIN-APPS-0002CLITwo records claim one project id from different repositoriesGive the copied app a new id with mainsdk init --new-id
MAIN-APPS-0003CLIA record says running but was last seen more than 5 minutes agoRestart the app, or remove the stale record
MAIN-APPS-0004checkCode reads the registry folder directly, or permissions.disk grants it, instead of apps.peer()Use apps.peer()
MAIN-APPS-0005checkA file that reads apps.peer() or apps.call() results also makes an outbound call; registry data may leave the machineSplit the code so peer data stays local
MAIN-APPS-0006runtimeA peer call between apps that don't both list each other under apps.peersList each app under the other's apps.peers
MAIN-APPS-0007runtimeA peer call to an action the callee doesn't list under apps.exposeList the action under the callee's apps.expose
MAIN-APPS-0008runtimeThe link handshake failed: the peer's proof doesn't verify with the identity key in its seal, or its seal is invalidRe-seal the peer and check its identity key
MAIN-APPS-0009runtimeapps.link: on without apps.identity and MAINSDK_APP_KEY; the link stays offSet apps.identity and MAINSDK_APP_KEY

ADOPT, ASSURE and CLOUD

CodeRaised byMeaningFix
MAIN-ADOPT-0001CLIadopt next before key flows are lockedRun mainsdk adopt lock first
MAIN-ASSURE-0003CLIThe record assure read from a URL has an invalid signature (exit 2)Treat the app's record as untrusted
MAIN-CLOUD-0402Cloud (phase 2)Free allowance used, after the warning and grace period. Only the Cloud answers it; your app keeps runningAdd a card with a cap, or move to Teams

MEM

Agent memory (spec memory, planned for 0.4).

CodeRaised byMeaningFix
MAIN-MEM-0001runtimeNo subject: about is missing and the call has no on_behalf_of or session user (400)Pass about, or call inside a session or an agent call made for a person
MAIN-MEM-0002runtimeNo memory with that id in the current tenant, app and scope (404, same body either way)Use an id returned in this tenant and app
MAIN-MEM-0003runtimeThe injection check flagged the text of a write; nothing was stored (422)Store what the person said, not instructions from a tool or page
MAIN-MEM-0004runtimeA recalled memory was flagged by the injection check and left out of the context (logged)Review the memory and forget it if it is an injection
MAIN-MEM-0005runtimeThe agent has no memory grant for this verb, or forget: deny (403)Add read or write under agents.<name>.memory on purpose
MAIN-MEM-0006runtimeThe agent is over its memory recalls or writes per day (429)Wait for the day to reset, or raise the limit on purpose
MAIN-MEM-0007runtimeForget refused: a legal hold applies to the person (409)Lift the hold with the person who set it, then forget
MAIN-MEM-0008runtimeA children's rule refused it: children are off, no guardian consent, or a provider model would extract (403)Set children: guardian and record the guardian's consent; use a local extract model
MAIN-MEM-0009runtimeInvalid input: unknown kind, bad duration, pan label, k over 100, hops over 2 or a bad predicate (400)Fix the argument the problem's errors member names
MAIN-MEM-0010runtimeRevise of a version that is no longer current (409)Read the current version with memory.history and revise that
MAIN-MEM-0011runtimeImport refused: a line is malformed, or personal or non-procedure memory would cross a tenant or app (422)Import into the same tenant and app, or export only procedure memories labelled none
MAIN-MEM-0012runtimeThe driver doesn't declare the capability the call needs, such as asOf, hops or relate (501)Drop the option, or use a driver that declares the capability
MAIN-MEM-0013runtimeThe memory store is unreachable (503, retryable); context degrades to an empty blockRetry; check the store and its region endpoint
MAIN-MEM-0014runtimeAn Anthropic memory tool path is outside /memories/ or tries to traverse (400)Keep paths under /memories/ with no .. or encoded separators
MAIN-MEM-0015runtimeA driver hasn't confirmed the erase yet; no receipt is issued and the erase keeps retrying (503)Wait for the retry job; the receipt follows the driver's confirmation
MAIN-MEM-0016runtimeA write from a tool, MCP, the web or an import was refused by from-tools: refuse (403)Ask the person to confirm the fact, or set from-tools: quarantine
MAIN-MEM-0020checkA driver that only soft-deletes holds memories that may be personalUse a driver with erase: hard, such as db
MAIN-MEM-0021checkA region the app serves has no endpoint in the memory driverAdd the region's endpoint, or use the db driver in that region
MAIN-MEM-0022checkRecalled memory is passed as the system text of an ai callPass memory.context() text in a user message as data
MAIN-MEM-0023checkA driver is named memory; the in-process driver is local (ADR-0039)Rename the driver to local
MAIN-MEM-0024checkchildren: guardian with an extract model on a providerUse a local extract model, or turn children off
MAIN-MEM-0025checkThe local memory driver in productionUse the db driver or a provider driver in production

PORT and SDK

Portable core (spec portable-core, planned for 0.4) and SDK conventions (spec sdk-conventions, planned for 0.3).

CodeRaised byMeaningFix
MAIN-PORT-0001checkmain.yaml uses an interface or driver that the declared targets.<name>.runtime can't run, such as disk on workerdMove that work to a target on Node, Bun or Deno, or drop the interface from this target
MAIN-PORT-0002runtimeA call reached the portable fallback of an adapter-only interface on a runtime without itCall it from a server target on Node, Bun or Deno
MAIN-PORT-0003runtimeA portable global the call needs is missing, such as crypto.subtle on an old runtimeUpgrade the runtime to one that implements the WinterTC Minimum Common API
MAIN-SDK-0001runtimeThe call was aborted through its signal; cause is the signal's reason. Never retriedNothing to fix if the abort was meant; otherwise don't abort the signal
MAIN-SDK-0002checkCode for a production target imports mainsdk/experimental/* (a warning)Use the stable subpath once the interface ships, or accept the risk on purpose

API

Spec app-api.

CodeRaised byMeaningFix
MAIN-API-0001runtime (start)An action's HTTP mapping is invalid: a GET on a write or destructive action, a path parameter that isn't a top-level string or integer input key, a nested field on a GET or DELETE, two actions on one method and path, or a name segment that isn't an identifier (500)Fix the mapping the error names: reads use GET, path parameters are top-level inputs
MAIN-API-0002runtimeAn Idempotency-Key was reused with a different input (422)Send a new Idempotency-Key for a new request
MAIN-API-0003runtimeThe first request with this Idempotency-Key is still running (409, retryable)Wait for the first request to finish, then retry
MAIN-API-0004runtimeAn action returned a value that fails its output schema; nothing of it is sent (500)Return a value that matches the output schema
MAIN-API-0005runtimeA risk listed under api.idempotency.require was called without Idempotency-Key (400)Send an Idempotency-Key header with the call
MAIN-API-0006runtimeThe major version was called after its sunset date (410)Move the client to the current major version
MAIN-API-0007clientThe generated client got no answer, or an answer that isn't problem details or JSON (retryable for network failures)Check the URL and the network; retry network failures
MAIN-API-0010checkAn action's input or output has no JSON Schema (a foreign schema without toJSONSchema()); the document and client type it as unknownUse a schema with toJSONSchema(), or a native one from mainsdk/schema
MAIN-API-0011checkThe committed snapshot at api.snapshot differs from what the code generatesRun mainsdk api openapi and commit the new snapshot
MAIN-API-0012check, CLImainsdk api diff found a breaking change in a major version that already shippedShip the change in a new major version, and keep the shipped one working

IMPORT

Spec imports.

CodeRaised byMeaningFix
MAIN-IMPORT-0001runtimeThe format or encoding isn't supported: not CSV, XLSX, JSON or NDJSON, not UTF-8, a JSON value that isn't an array, a legacy .xls or an encrypted workbook (415)Convert the file to CSV, XLSX, JSON or NDJSON in UTF-8
MAIN-IMPORT-0002runtimeThe file is over a limit: max-rows, max-columns, json-max or the files size (413); rows up to the limit are not writtenSplit the file, or raise the limit under imports
MAIN-IMPORT-0003runtimeThe mapping is incomplete or unconfirmed: a required field has no column, a mapped column doesn't exist, or a field would come from a model suggestion not passed back in mapping (422)Map every required field to a column, and confirm the suggested mapping
MAIN-IMPORT-0004runtimeThe file isn't ready yet (still scanning) (409, retryable)Wait for the scan to finish, then retry
MAIN-IMPORT-0005runtimeThe run stopped because failed rows passed maxErrors; the report lists them (422)Fix the rows the report lists, then run again
MAIN-IMPORT-0006runtimeAn unsafe workbook: a zip entry over the size or ratio limit, a path outside the archive, or XML with a DOCTYPE or entity (422)Save the workbook again without the flagged parts
MAIN-IMPORT-0010runtime (logged)A pull failed: the source was unreachable or refused; the cursor is unchanged and the next run retriesCheck the source's address and credentials; the next run retries
MAIN-IMPORT-0011runtime (logged)The deletion guard tripped: a full pass returned fewer keys than deletes-guard, so nothing was deletedCheck the source; raise deletes-guard only on purpose
MAIN-IMPORT-0012runtime (logged)The source rejected the stored cursor; a full pass is scheduledNothing to fix; the full pass runs
MAIN-IMPORT-0020checkA source under imports.sources has no imports.source() in the code, or the code defines a source main.yaml doesn't declareDeclare each source in both main.yaml and the code

CONN

Spec connections. The MCP codes that the connections spec adds are under AI, MCP and actions.

CodeRaised byMeaningFix
MAIN-CONN-0001runtimeThe provider isn't under connections.providers (500 at start for config, 400 for a call)Declare the provider under connections.providers
MAIN-CONN-0002runtimeNo active connection to this provider for this person or tenant (403); the fix names connections.connectAsk the person to connect with connections.connect
MAIN-CONN-0003runtimeThe connection wasn't granted the scope this call needs (403); the fix asks to connect again with itAsk the person to connect again with that scope
MAIN-CONN-0004runtimeThe agent may not use this scope: it isn't under agents.<name>.connections.<provider> (403); nothing is sentAdd the scope under agents.<name>.connections.<provider>
MAIN-CONN-0005runtimeThe URL's host isn't one of the provider's hosts, or isn't https; the token is not sent (403)Call an https host the provider lists under hosts
MAIN-CONN-0006runtimeThe callback was refused: state missing, unknown, expired, used or from another session, code verifier rejected, or issuer mismatch (400)Start the connect flow again
MAIN-CONN-0007runtimeThe connection expired or was revoked at the provider (invalid_grant), or its key was destroyed; connect again (401)Ask the person to connect again
MAIN-CONN-0008runtimeThe provider couldn't be reached to refresh an expired token (503, retryable)Retry when the provider is reachable
MAIN-CONN-0009runtimeconnect asked for a scope beyond providers.<name>.scopes (400); nothing is sentRequest only scopes listed under providers.<name>.scopes
MAIN-CONN-0020checkAn agent or step-up names a scope not under its provider's scopes, or a provider not under connections.providersName only scopes and providers declared under connections
MAIN-CONN-0021checkA provider has no preset and no hosts, so no call could be sentUse a preset, or list the provider's hosts

SEED and PREVIEW

Spec seed-preview.

CodeRaised byMeaningFix
MAIN-SEED-0001runtimeSeed or fixtures refused: the resolved environment is production (nothing is opened or written)Run seed and fixtures outside production
MAIN-SEED-0002runtimeSeed refused: the target database is not seedable (not local, not a preview, no seedable marker)Seed a local or preview database that carries the seedable marker
MAIN-SEED-0003runtimeA field can't be generated from its schema (an unsupported pattern or a refine); set a generator under seed.modelsSet a generator under seed.models for that field
MAIN-SEED-0004runtimeAI text unavailable or over seed.ai.limit; built-in text was used and the run went onNothing to fix; raise seed.ai.limit or check the AI driver if you want AI text
MAIN-PREVIEW-0001runtimeThe db driver has no branching capability; use preview.driver: local or a driver that has itUse preview.driver: local, or a db driver with branching
MAIN-PREVIEW-0002runtimeThe provider refused or failed while making the preview; what was made was deletedCheck the provider's status and credentials, then retry
MAIN-PREVIEW-0003runtimeRefused to delete or seed the parent, or a database the preview driver did not makePoint the preview at a database it made
MAIN-SEED-0010checkseed or preview is active in production, or app code outside tests and scripts imports the seed engineKeep seed and preview out of production; import the seed engine only in tests and scripts
MAIN-SEED-0011checkA literal under seed.models looks like real personal data (an email outside the reserved domains, a phone number outside the reserved ranges)Use reserved example values, such as example.com emails and reserved phone ranges

ENGAGE

Spec engagement.

CodeRaised byMeaningFix
MAIN-ENGAGE-0001runtimeEngagement message skipped: the person reached the weekly limitNothing to fix; the message waits for next week
MAIN-ENGAGE-0002runtimeEngagement messages stopped for this person: stop-after-ignored messages in a row were ignoredNothing to fix; the person can opt back in
MAIN-ENGAGE-0003runtimeAI copy was refused by the copy rules, was over the tenant's copy.limit, or failed; the template text was usedNothing to fix; raise copy.limit or fix the copy rules if you want AI copy
MAIN-ENGAGE-0004runtimeGuardian control refused: the caller isn't the child's guardian, or the change loosens a limit (403)Ask the child's guardian to make the change
MAIN-ENGAGE-0005runtimeNot sent to a children's audience: the copy has streak-loss or guilt pressure, or comparative social proofRemove streak-loss, guilt pressure and comparative social proof from the copy
MAIN-ENGAGE-0006runtimeurgent: true on an engagement message refused; engagement never skips quiet hours (400)Remove urgent: true
MAIN-ENGAGE-0007runtimeA social proof placeholder had no declared query, or its result was hidden or empty; the text without proof was usedDeclare a query for the placeholder, or accept the text without proof
MAIN-ENGAGE-0008runtimeA guardrail value in main.yaml is invalid (start fails), or a pushed value loosens one (refused, last good kept)Fix the guardrail value in main.yaml
MAIN-ENGAGE-0010checkConfirmshaming in unsubscribe or opt-out copyWrite neutral unsubscribe copy
MAIN-ENGAGE-0011checkSocial proof not backed by data: a literal count or name ("1,240 people finished today") instead of a {{proof.*}} placeholderUse a {{proof.*}} placeholder backed by a declared query
MAIN-ENGAGE-0012checkEngagement messages are sent (journey, ladder, engagement.send or an engagement category) with no notify.engagement.max-per-weekSet notify.engagement.max-per-week
MAIN-ENGAGE-0013checkA children's audience is possible with no notify.engagement.guardian settingsSet notify.engagement.guardian
MAIN-ENGAGE-0014checkCopy that can reach a children's audience has streak-loss or guilt pressure, or comparative social proofRemove streak-loss, guilt pressure and comparative social proof from that copy

Spec search.

CodeRaised byMeaningFix
MAIN-SEARCH-0001runtimeThe index isn't declared under search.indexes (400)Declare the index and its fields under search.indexes
MAIN-SEARCH-0002runtimeThe access filter for this searcher can't be expressed in the engine's query; refused, never post-filtered (403)Use an access driver that lists for this resource type, or store the fields the filter needs in the index
MAIN-SEARCH-0003runtimesearch.query without for, outside tenant.system (400)Pass the searcher as for
MAIN-SEARCH-0004runtimeThe engine is unreachable or the query passed timeout (503, retryable); index changes stay queuedRetry; restore the engine; changes apply when it is back
MAIN-SEARCH-0005runtimeA filter, sort or facet names a field not declared for it, or a reserved field (_tenant, _region, _v) (400)Declare the field as filter, sort or facet; never filter on reserved fields
MAIN-SEARCH-0006runtimeNo index endpoint for the tenant's region; the change stays queued and is sent nowhere else (logged)Add an endpoint for that region under the driver's regions
MAIN-SEARCH-0007runtimeA cursor would go past max-depth (400)Refine the query or filters
MAIN-SEARCH-0008runtimeq is longer than 512 characters, or a filter value has the wrong type for its field (400)Shorten the query or send a value of the field's type
MAIN-SEARCH-0009runtimeAn index change failed after its last retry and is in the dead-letter queue; counted in search.statusRead the dead-letter entry, fix the cause and run mainsdk search reindex
MAIN-SEARCH-0010checkAn index's access filter needs a field the index doesn't store, or the access driver's profile can't list for that resource typeAdd the field to the index, or use an access driver that lists
MAIN-SEARCH-0011checkA field labelled sensitive, phi, child or secret is indexed without index: allow on the fieldRemove the field from the index, or add index: allow with a reason
MAIN-SEARCH-0012checkAn engine driver has no endpoint for a region the app stores data inAdd an endpoint per region under the driver's regions
MAIN-SEARCH-0013checkAn engine SDK (typesense, meilisearch, algoliasearch) imported outside a driverCall search instead
MAIN-SEARCH-0014checksearch.query without for in a file outside tenancy.system.allowPass the searcher as for

FEED

Spec feeds.

CodeRaised byMeaningFix
MAIN-FEED-0001runtimeFollow, request or profile read refused: one side blocks the other (403)None; the block stands until it is removed
MAIN-FEED-0002runtimeA follow or item across tenants (403)Keep follows and items inside one tenant
MAIN-FEED-0003runtimeThe item doesn't exist, is removed, or isn't visible to the viewer (404)Use an id the viewer may see
MAIN-FEED-0004runtimeEdit or remove by someone who isn't the author and whom access doesn't allow feeds.remove (403)Let the author act, or grant feeds.remove to moderators
MAIN-FEED-0005runtimeFollowing more than max-following (422)Unfollow someone first
MAIN-FEED-0006runtimeA fan-out batch failed after its last retry and is in the dead-letter queue; affected timelines are served by merging at read time (logged)Fix the cause and retry the dead-letter entry
MAIN-FEED-0007runtimeThe ranker threw, returned an entry without a reason, or passed ranked.budget; the chronological timeline was served (logged)Fix the ranker so it returns a reason for every entry within the budget
MAIN-FEED-0008runtimeA pushed value loosens page.end, page.pause_after, trending.min-count or max-following; refused, last good keptPush only tighter values, or change main.yaml in a reviewed deploy
MAIN-FEED-0010checkA feed with no end: page.end: false, page.pause_after off or above 500, or a client that requests the next page with no user actionKeep page.end: true, set pause_after to 500 or less, and load more only on a person's action
MAIN-FEED-0011checktimeline.order: ranked, or a feeds.ranker, in an app with a children's audience and no chronological-only rule for itServe children the chronological timeline
MAIN-FEED-0012checktrending.min-count below 10, or a trending key built from a labelled fieldRaise min-count to 10 or more; build keys from tags or item ids
MAIN-FEED-0013checkfanout.threshold above 100,000, timeline.max above 5,000 or max-following above 50,000Lower the value to its ceiling

MOD

Spec moderate.

CodeRaised byMeaningFix
MAIN-MOD-0001runtimeReport refused: the person passed reports.per-user, or already reported this target (429)None; the person can report again later
MAIN-MOD-0002runtimeUnknown reason, or the target doesn't exist in the current tenant (400)Use a reason from moderate.reasons and a target in this tenant
MAIN-MOD-0003runtimeThe caller lacks moderate.review, or the case is assigned to someone else (403)Grant moderate.review, or assign the case to the caller
MAIN-MOD-0004runtimeAppeal refused: outside appeals.window, already appealed, or the decision isn't the caller's to appeal (409)None; one appeal per decision, by its author, within the window
MAIN-MOD-0005runtimeAn appeal resolved by the reviewer who made the decision (403)Assign the appeal to another reviewer
MAIN-MOD-0006runtimeA pre-screen driver is unreachable or failed; the content stays held and is retried, then queued for people after hold.max (logged)Restore the driver; held content clears when it is back
MAIN-MOD-0007runtimeKnown-abuse hash match: the content is blocked and never published; logged with the list name, never the contentFollow your legal duty through the onMatch handler
MAIN-MOD-0008runtimeA decision other than none without a ground or facts (400)Name the terms clause or law and the facts
MAIN-MOD-0009runtimeHeld, blocked or removed content read through files.url, media.url or feeds (403)Wait for the pre-screen to clear it
MAIN-MOD-0010checkA hash list or hash database in the repository or the build outputDelete it; fetch lists from your provider at run time under prescreen.hash.lists
MAIN-MOD-0011checkUser content is published (feeds.publish, share of an upload, a public file URL) with no moderate sectionAdd a moderate section with hold and reports
MAIN-MOD-0012checkNo moderate.reports.per-user, or one above 100 an hourSet reports.per-user to 100 an hour or less
MAIN-MOD-0013checkappeals off or a window under 6 months, or remove-on lists a label other than spamKeep appeals on for at least 6 months; send other labels to hold-on

MEDIA

Spec media.

CodeRaised byMeaningFix
MAIN-MEDIA-0001runtimeThe source file isn't ready, doesn't exist in the current tenant, or the caller may not read it (404)Complete the upload first and pass a file the caller may read
MAIN-MEDIA-0002runtimeThe source is over a limit: duration, size or pixels; the job failed in the probe step, nothing was transformed (422)Ask for a smaller file, or raise the limit up to its ceiling
MAIN-MEDIA-0003runtimeThe source's magic bytes don't match a supported type, or don't match its declared type (415)Upload a supported image, video or audio file
MAIN-MEDIA-0004runtimeThe driver doesn't support this kind or format, such as an image on mux (501)Use a driver whose profile lists the kind
MAIN-MEDIA-0005runtimeA transform step failed after its last retry: the provider failed, or ffmpeg exited non-zero; the job is failedRead the step's error and start a new job
MAIN-MEDIA-0006runtimeNo job with that id in the current tenant (404)Use a job id from this tenant
MAIN-MEDIA-0007runtime, checkmedia.keep lists gps, location or an unknown metadata name (start fails; check finding)Keep only icc and orientation-tag
MAIN-MEDIA-0010check, runtimeThe ffmpeg driver in productionUse getqr, mux or cloudinary in main.env.prod.yaml
MAIN-MEDIA-0011checkAn image or video library (sharp, jimp, fluent-ffmpeg, @ffmpeg/ffmpeg, ffmpeg-static) or an ffmpeg program run outside a driverCall media instead
MAIN-MEDIA-0012checkdelivery: provider on mux or cloudinary: outputs served by the provider, outside files (named gap)Use delivery: files, or accept the gap
MAIN-MEDIA-0013checkA media kind used with no limits, or a limit above its ceiling: max-duration over 4h, max-size over 10GB, max-pixels over 100MPDeclare limits for each kind within the ceilings

METER and LIMIT

CodeRaised byMeaningFix
MAIN-METER-0001runtime, checkA metric not declared under meter.metricsDeclare the metric with its unit and aggregate
MAIN-METER-0002runtimeA value that isn't finite, is negative for sum or count, or an at outside its window (400)Record a valid value at a time within 35 days back and 1 hour ahead
MAIN-METER-0003runtimeThe buffer was full while the store was down, so the oldest records were dropped (logged with the count)Restore the store; raise meter.buffer if outages are long
MAIN-METER-0004runtimeUsage was served from the last known value because the store can't be reached (stale: true)Restore the store
MAIN-METER-0005runtimeAn export to pay failed for a tenant and hour; retried with the same identifierCheck the pay driver and the provider's meter name
MAIN-METER-0006check, runtimemeter is invalid: unknown aggregate, unique without of, an exported metric with no provider meter, keep under 35 days, or local in productionFix the key the finding names
MAIN-METER-0007runtimeNo meter store for the tenant's region; the record is refused, never written elsewhereAdd a store for that region under meter
MAIN-METER-0008runtimeA usage window is invalid: from after to, not on whole hours, or over 13 months (400)Pass a calendar window or a whole-hour range
MAIN-LIMIT-0001runtimeThe rate limit for this policy and key is reached (429, with Retry-After)Wait Retry-After seconds
MAIN-LIMIT-0002runtimeThe quota for this window is used up (429, with Retry-After)Wait for the window to reset
MAIN-LIMIT-0003runtimeNo concurrency slot came free within wait (429, with Retry-After)Retry later, or raise max on purpose
MAIN-LIMIT-0004runtimeThe lock wasn't acquired within wait (409, retryable)Retry, or pass a longer wait
MAIN-LIMIT-0005runtimeRefused because the store is down and the policy's on-store-down is closed (503, with Retry-After)Restore the limits store
MAIN-LIMIT-0006runtime, checkA policy, quota or concurrency name not declared under limitsDeclare it under limits
MAIN-LIMIT-0007check, runtimeA policy is invalid: max under 1, a bad per, an unknown algorithm or key, burst under max, or a ttl over 1 hourFix the key the finding names
MAIN-LIMIT-0008check, runtimeThe local limits driver in production without single-instance: trueUse redis, or set single-instance: true for one instance
MAIN-LIMIT-0009runtimeA lock or concurrency lease expired before the work finished; its signal was aborted (logged)Raise ttl, or check the store's health

COMPUTE

CodeRaised byMeaningFix
MAIN-COMPUTE-0001runtime, checkA target not declared under compute.targetsDeclare the target
MAIN-COMPUTE-0002runtimeRefused before submit: the worst case (price times timeout) passes maxCost, a compute.limits ceiling or the agent's budget (402)Lower the timeout, raise maxCost on purpose, or wait for the period
MAIN-COMPUTE-0003runtimeThe running cost reached maxCost; the job was cancelled at the providerRaise maxCost on purpose, or make the job cheaper
MAIN-COMPUTE-0004runtimeNo heartbeat for three periods; the job is lost and was cancelled at the providerCheck the provider; start the job again
MAIN-COMPUTE-0005runtimeThe provider failed submit, status or cancel after retries (502)Check the provider's status and your account
MAIN-COMPUTE-0006runtimeThe job passed its timeout and was cancelledRaise the target's timeout on purpose
MAIN-COMPUTE-0007runtimeLabelled input to a target outside the tenant's region (403)Use a target in the tenant's region
MAIN-COMPUTE-0008checkA target isn't pinned: no model version, app or endpoint idPin the version or id
MAIN-COMPUTE-0009runtimeAn output is too large or of a type not in compute.results.types (413 or 415)Raise the limit or allow the type on purpose
MAIN-COMPUTE-0010runtimeNo job with that id in the current tenant (404)Use an id from compute.list
MAIN-COMPUTE-0011runtimeCancel of a finished job (409)Nothing to cancel
MAIN-COMPUTE-0012runtimeA provider callback failed verification (400)Check the provider's webhook secret
MAIN-COMPUTE-0013check, runtimeA target has no price or timeout, or a timeout over 24hSet both, with a timeout of 24h or less

MAIL and CAL

CodeRaised byMeaningFix
MAIN-MAIL-0001runtimeNo mailbox or route matches the recipient; dropped and loggedAdd a mailbox or a mail.on route for the address
MAIN-MAIL-0002runtimeA raw message can't be parsed, or passes the size, part or nesting limitNothing to fix in code; the record keeps the headers
MAIN-MAIL-0003runtimeRejected by mail.reject: DMARC failed or a virus was foundNothing to fix; the sender's domain or file is the problem
MAIN-MAIL-0004runtimeAn attachment was refused by size, type or scan; a placeholder is keptRaise mail.attachments.max-size on purpose if needed
MAIN-MAIL-0005runtimeA reply address token is invalid, expired or for another tenant; threaded by headers insteadNothing to fix; raise mail.reply.expires if replies come late
MAIN-MAIL-0006runtimeAn IMAP or JMAP server failed or timed out during a pull; retriedCheck the provider's status
MAIN-MAIL-0007runtimeA mailbox's cursor can't be continued; it is pulled again from the startNothing to do
MAIN-MAIL-0008check, runtimemail is invalid: a mailbox outside domains, an inbound provider with no secret, or a pull provider not under connections.providersFix the key the finding names
MAIN-MAIL-0009checkCode listens for SMTP: a server on port 25, 465 or 587, or an SMTP server packageReceive mail through mail and a provider webhook (ADR-0052)
MAIN-MAIL-0010runtimeAn Authentication-Results header from a server other than the provider's was ignoredNothing to fix; it may be a spoofing attempt
MAIN-CAL-0001runtime, checkAn event is invalid: end before start, an unknown IANA zone, a date-time mixed with a date, or no title (400)Fix the field the error names
MAIN-CAL-0002runtime, checkA recurrence rule is invalid or uses an unsupported part (400)Use the parts the calendar page lists
MAIN-CAL-0003runtimeA window passes max-window, or the expansion passes max-occurrences (400)Ask for a shorter window
MAIN-CAL-0004runtimeiCalendar text can't be parsed at a line; that event is skippedFix the line, or accept the skip
MAIN-CAL-0005runtimeAn import is larger than calendar.max-import (413)Split the file, or raise the limit on purpose
MAIN-CAL-0006runtimeNo calendar with that id in the tenant, or access denies it (404 or 403)Use a calendar the person may read
MAIN-CAL-0007runtimeAn edit scope that doesn't fit the event or occurrence (400)Use all for a single event, and an occurrence from the series
MAIN-CAL-0008runtimeThe event changed since version was read (409)Read it again and reapply the change

INCIDENT

CodeRaised byMeaningFix
MAIN-INCIDENT-0001runtimeSwitched off by an incident control (503, retryable)Wait for the control to clear, or clear it with mainsdk incident off
MAIN-INCIDENT-0002runtimeThe app is read-only during an incident (503 for requests; thrown by writes)Wait for mainsdk incident off read-only, or use a path in read-only-allow
MAIN-INCIDENT-0003runtimeThe session was issued before the incident sign-out cut-off (401)Sign in again
MAIN-INCIDENT-0004check, runtimeA kill target is unknown or malformed, or names a protected interfaceName an existing action, route, interface, driver or agent
MAIN-INCIDENT-0005runtimemainsdk incident could not write: no --reason, or the config driver has no writePass --reason, or use a config driver with write and set the key by hand
MAIN-INCIDENT-0006runtimeincident.set refused: no incident.manage, or no fresh phishing-resistant session (403)Grant incident.manage, and sign in again with a passkey
MAIN-INCIDENT-0007check, runtimeA control with no expires has been in force for 24 hours (warn)Add --expires to the control, or clear it when it is no longer needed

PROTECT

Codes from protected files (spec protect-taps, planned for 0.4). Runtime codes are also listed in errors.

CodeRaised byMeaningFix
MAIN-PROTECT-0001runtimeLicence denied by the policy (403); the TAPS error type is in taps, the failed condition only in the decision logCheck the asset's policy with protect.policy.check(); read the decision log record
MAIN-PROTECT-0002runtimeTime-locked: before releaseAt, or the release round isn't available yet (403, retryAfter)Wait for the release time
MAIN-PROTECT-0003runtimeThe asset, the person's access, the link or the licence was revoked, or the asset was erased (403; 410 when erased)Protect and share a new copy if access should continue
MAIN-PROTECT-0004runtimeNo such asset, version, link, delegation or approval in this tenant (404, same body either way)Check the id and the current tenant
MAIN-PROTECT-0005runtimeA person must approve first; the problem carries approvalId and retryAfter (403)Approve with protect.approvals.update(), or pass approvals
MAIN-PROTECT-0006runtimeThe approver declined, or the approval timed out (403)Ask again, or extend the approval before it times out
MAIN-PROTECT-0007runtimeDelegation invalid: wider than the person, expired, revoked, used up or deeper than 3 (403)Create a delegation within what the person may do
MAIN-PROTECT-0008runtimeA query or play budget, or a delegation's maxUses, is used up (429)Wait for the budget to reset, or raise it in the policy
MAIN-PROTECT-0009runtimeA session, print, device or recipient-verification rate limit was passed (429, retryAfter)Retry after retryAfter
MAIN-PROTECT-0010runtimeSuite not supported: TAPS-CS3 is refused until it is registered; no post-quantum protection is claimed (400)Use TAPS-CS1 or TAPS-CS2
MAIN-PROTECT-0011runtimeThreshold release not reached: fewer than t parties have released (403, retryable)Wait for more parties; see protect.threshold.get()
MAIN-PROTECT-0012runtimeThe asset or its label is locked down, suspended or quarantined (423)Lift the lockdown with approvals, or replace a quarantined file
MAIN-PROTECT-0013runtimeStep-up required: the policy needs a fresher or stronger sign-in, listed in requirements (401)Sign in again with the listed method
MAIN-PROTECT-0014runtimeThe TAPS Node, a threshold party or the sealing service is unreachable (503, retryable); nothing opens without a licenceCheck protect.url and the network; retry
MAIN-PROTECT-0015runtimeInvalid input: unknown policy key, label pan, a zone id that isn't opaque, t outside 2 to n, releaseAt in the past, an unknown party or an undeclared agent (400)Fix the call; protect.policy.lint() names policy issues
MAIN-PROTECT-0016runtimeThe file's version is superseded; location names the current version (409)Open the current version
MAIN-PROTECT-0017runtimeThe ledger is stale or the registration is pending (503, retryAfter)Retry after retryAfter
MAIN-PROTECT-0018runtimeA query answer was refused by the output controls: the whole document, a verbatim span over the limit, or a denied field (422)Ask a narrower question
MAIN-PROTECT-0019runtimeThe driver's profile lacks the capability the call needs, such as query or web3 (501)Use a driver whose profile has it
MAIN-PROTECT-0020checkA @taps/* package is imported outside @mainsdk/protect-tapsCall protect instead
MAIN-PROTECT-0021checkThe protect section is invalid: unknown key or driver, no url or share-domain for a taps-* driver, no key, suite: TAPS-CS3, renew outside 5s to 5m, or a threshold party without a URLFix the section the finding names
MAIN-PROTECT-0022checkA production build resolves @taps/* from a folder (link: or file:) instead of the registryInstall @taps/* from npm once published; until then don't ship @mainsdk/protect-taps to prod

LICENCE

Codes from app licensing (spec licence, built, and spec licence-cloud, planned for 0.6). The check reports 0011, 0012 and 0014; the rest are raised at runtime. Not TAPS licences: those are MAIN-PROTECT. Runtime codes are also listed in errors.

CodeRaised byMeaningFix
MAIN-LICENCE-0001runtimeThe feature needs a licence and the licence in scope doesn't include it, or isn't valid or in grace (403, with licence: { feature, status, reason })Run mainsdk licence show; install a licence that includes the feature with licence.update()
MAIN-LICENCE-0002runtimeA licensed limit is reached: the licence's ceiling is the one that binds (403, with licence: { name, limit })Ask the vendor for a licence with a higher limit, or set licence.over: report
MAIN-LICENCE-0003runtimeA licensed limit was passed with over: report; the call was allowed. Logged once per limit and scope per UTC dayRenew the licence with a higher limit before the true-up
MAIN-LICENCE-0004runtimeA licence, CA certificate or revocation list doesn't verify; reason is signature, chain, format, subject, binding, rollback or test-root (400 from licence.update())Ask the issuer for a new file; check licence.roots, licence.product, project and the environment
MAIN-LICENCE-0005runtimeThe licence is in grace: expiring, revoked or suspended. Warned once a day with graceEndsAtRenew the licence, or let refresh fetch the renewed one
MAIN-LICENCE-0006runtimeThe licence is expired, revoked or suspended past its grace; licensed features are offInstall a renewed licence; the rest of the app keeps serving
MAIN-LICENCE-0007runtimeNo licence, or not yet valid; licensed features are offSet licence.file or licence.token, or install one with licence.update()
MAIN-LICENCE-0008runtimeRefresh failed, or the newest revocation list is past its nextUpdate; the current state is kept. Logged once per outageCheck licence.url and the network; nothing is blocked meanwhile
MAIN-LICENCE-0009runtimeAn older licence (seq) or revocation list (number), or a different list with the same number, was refused; the newer one staysInstall the newest licence; report repeated attempts as a security event
MAIN-LICENCE-0010runtimeThe clock is behind the high-water time by more than licence.skew; the high-water time is used for licence decisionsFix the machine's clock (NTP)
MAIN-LICENCE-0011check, runtimeThe licence section is invalid: unknown driver or key, no product, no roots or more than 4, a root that isn't ed25519: and 32 bytes, both file and token, http without url, refresh outside 5m to 7d, skew outside 0 to 1h. The app doesn't startFix the key the finding names
MAIN-LICENCE-0012checkA feature name passed to licence.has or licence.require isn't under licence.featuresAdd the name to licence.features, or fix the typo
MAIN-LICENCE-0013runtimeA feature name that isn't under licence.features: has returns false and logs once; require throws (500)Add the name to licence.features, or fix the typo
MAIN-LICENCE-0014checkThe test root is pinned under licence.roots in productionPin your own root from MainSDK Cloud or your issuer
MAIN-LICENCE-0015runtimeThe machine id can't be read: no /etc/machine-id for machine: os, or MAINSDK_MACHINE_ID unset for machine: env (500)Set licence.machine: env and MAINSDK_MACHINE_ID, or use a licence with no machine binding
MAIN-LICENCE-0016runtimelicence.update refused: no licence.manage permission, an app licence outside tenant.system() in a tenanted app, or a tenant licence for another tenant (403)Grant licence.manage, or install the licence in its own tenant
MAIN-LICENCE-0020runtimeCloud: the caller lacks the role, or a write has no passkey session from the last 5 minutes (403)Sign in again with a passkey; ask an owner for licences:admin
MAIN-LICENCE-0021runtimeCloud: the licence claims are invalid; errors names each field (422)Fix the fields; see spec licence-cloud for the issuing rules
MAIN-LICENCE-0022runtimeCloud: no such root, CA or licence in this account (404)Check the id and the account
MAIN-LICENCE-0023runtimeCloud: the change conflicts with the state, such as renewing a revoked licence or issuing from a retired CA (409)Read the resource's status; issue a new licence or use the active CA
MAIN-LICENCE-0024runtimeCloud: a second approver is needed; the problem carries approvalIdAsk another admin to approve
MAIN-LICENCE-0025runtimeCloud: more than 60 refresh calls for one licence in an hour (429, Retry-After)Wait for Retry-After; keep licence.refresh at 5m or more
MAIN-LICENCE-0026runtimeCloud: the key service can't sign; nothing was issued or changed (503, retryable)Retry; apps keep verifying offline meanwhile

Modern AI: multimodal, images, video, agent loop, routing and local models

Specs ai-multimodal, ai-image, ai-run and ai-routing (planned for 0.4), ai-local (planned for 0.5) and ai-video (planned for 0.6).

CodeRaised byMeaningFix
MAIN-AI-0040runtimeA prompt part is invalid: unknown type, no file, a mime that doesn't match the bytes, pages out of order, or video given as bytes (400); nothing is sentPass a FileRef of a supported type, and let MainSDK read the type
MAIN-AI-0041runtimeA prompt part is over a limit: size, pixels, pages, duration, frames or max-parts (413); nothing is sentSend a smaller file or fewer parts, or raise ai.input on purpose
MAIN-AI-0042runtimeThe model or driver doesn't accept this kind of part (501)Use a model whose driver declares the modality
MAIN-AI-0043runtimeA labelled image, audio or scan would go to a driver whose data use or region doesn't meet the rules, and media can't be redacted (403)Use a driver that meets ai.data with an endpoint in the tenant's region
MAIN-AI-0044checkA prompt part is built from request body bytes or a data: URL instead of a FileRefUpload through files and pass the FileRef
MAIN-AI-0045runtimeAn image option is invalid: size, count, mask size or an empty prompt (400); nothing is sentPass a size from ai.image.sizes, a count within max-count and a mask the image's size
MAIN-AI-0046runtimeThe image driver doesn't offer this operation (501)Use a driver that declares edit, inpaint or variations
MAIN-AI-0047runtimeThe provider refused the image prompt under its content policy (422)Change the prompt; the reason code is in the audit event
MAIN-AI-0048runtimeA content credential couldn't be signed and ai.credentials.required is true (500)Restore the signer key in keys, or check its certificate
MAIN-AI-0049checkAI images are generated with no ai.credentials.signer (warning)Set a signer so images carry C2PA content credentials
MAIN-AI-0050runtimeA video option is invalid: seconds, size, prompt or references (400); nothing is sentPass values within ai.video and the driver's limits
MAIN-AI-0051runtimeNo video job with that id in the current tenant (404)Use a job id returned in this tenant
MAIN-AI-0052runtimeThe provider failed or refused the video job; the job is failedRead the reason code; change the prompt or retry later
MAIN-AI-0053runtimeA video job lost its provider heartbeat and was cancelled at the providerRetry the job; check the provider's status
MAIN-AI-0060runtimeAn ai.run option is invalid: goal and messages, maxSteps, budget, timeout or agent (400); nothing is sentPass one of goal or messages, a declared agent and limits within range
MAIN-AI-0061runtimeThe run stopped at maxSteps (stop: "max-steps")Raise maxSteps on purpose, or narrow the goal or tools
MAIN-AI-0062runtimeThe run stopped at its budget (stop: "budget")Raise the run's budget within the agent's, or use a cheaper model
MAIN-AI-0063runtimeThe run stopped at its timeout (stop: "timeout")Raise timeout, or use durable: true for long runs
MAIN-AI-0064runtimeThe model asked for a tool that isn't in the run's tools; the step was refusedNothing, if the tool shouldn't be reachable; otherwise add its action to tools
MAIN-AI-0065runtimeA handoff or delegation names an agent not declared for it (400)Add the agent under agents.<name>.run.handoff or delegate
MAIN-AI-0066runtimeA delegation asked for more than the parent's remaining budget or the declared share (402)Delegate less, or raise the declared share on purpose
MAIN-AI-0067runtimeNo run with that id in the current tenant, or it isn't waiting (404 or 409)Use a run id from this tenant that is waiting
MAIN-AI-0068checkA tool passed to ai.run isn't ai.tool() of a declared actionDeclare the tool with action() and pass ai.tool(action)
MAIN-AI-0070checkA route lists a model not in ai.models, unpriced, or whose driver doesn't meet ai.dataRemove the model from the route, or fix its allowlist, price or driver
MAIN-AI-0071runtimeEvery model in the route failed with a retryable error (502)Check the providers' status; add another model that meets the rules
MAIN-AI-0072runtimeA fallback model was skipped because its endpoint is outside the tenant's region for labelled data (logged)Add a model with an endpoint in that region to the route
MAIN-AI-0073runtime, checkA response cache entry is invalid: tenant scope with labelled data, a TTL over 7 days, or local kv in productionUse scope: user, a shorter TTL, or a production kv driver
MAIN-AI-0074runtimeA batch option is invalid: no items, too many, duplicate ids, or no batch API (400)Fix the items, or use a driver with a batch API
MAIN-AI-0075runtimeNo batch with that id in the current tenant (404)Use a batch id returned in this tenant
MAIN-AI-0076runtimeThe store that counts ai.limits did not answer and the call is under a spend limit, so it is refused (503, retryable)Check runtime.store; calls under no limit keep running
MAIN-AI-0078runtimeThe local model server is unreachable (503, retryable)Start it, for example ollama serve
MAIN-AI-0079checkA local endpoint uses plain HTTP off the machine, isn't in network.allow, or a remote one lacks data or regionUse HTTPS, allow the host, and declare its data use and region
MAIN-AI-0080runtimeThe model isn't on the local server (404)Fetch it, for example ollama pull llama3.2:3b

DOC

Documents (spec documents, planned for 0.4).

CodeRaised byMeaningFix
MAIN-DOC-0001runtimeThe file isn't a supported document type, or its bytes don't match its declared type (415)Send a PDF, DOCX, XLSX, PPTX, PNG, JPEG or TIFF
MAIN-DOC-0002runtimeOver a limit: size, pages, ZIP expansion, or more pages than inline-pages for parse (413)Use documents.start for large files, or raise documents.limits on purpose
MAIN-DOC-0003runtimePages have no text layer and OCR is off or no OCR driver is set (422)Set documents.ocr.driver, or pass ocr: "auto"
MAIN-DOC-0004runtimeThe documents driver doesn't offer this (501)Use a driver that declares the capability
MAIN-DOC-0005runtimeThe PDF is encrypted or password protected (422)Ask for an unprotected copy
MAIN-DOC-0006runtimeActive content was found and not run (logged)Nothing to do; review findings if the file is suspicious
MAIN-DOC-0007runtimeA render layout or template is invalid (400)Fix the element, template name, font or value the error names
MAIN-DOC-0008runtimeA labelled document would go to a driver outside the tenant's region or not meeting the data rules (403)Add an endpoint for the region, or use a driver that meets ai.data
MAIN-DOC-0009runtimeNo document job with that id in the current tenant (404)Use a job id returned in this tenant
MAIN-DOC-0010checkA PDF or Office library used outside a driverCall documents instead
MAIN-DOC-0011checkA locale with a complex script renders with the builtin renderer, which doesn't shape itUse the gotenberg or docraptor render driver

SANDBOX

Running untrusted code (spec sandbox, planned for 0.4).

CodeRaised byMeaningFix
MAIN-SANDBOX-0001runtimeA sandbox option is invalid (400); nothing ranFix the language, code, limit or path the error names
MAIN-SANDBOX-0002runtimeThe code reached its time limit and was killedRaise timeout within sandbox.limits, or make the code faster
MAIN-SANDBOX-0003runtimeThe code passed its memory limit and was killedRaise memory within sandbox.limits
MAIN-SANDBOX-0004runtimeOutput or files passed their limit; output is cutWrite less, or raise limits.output on purpose
MAIN-SANDBOX-0005runtimeA host isn't in sandbox.network and network.allow, or the code tried a host it wasn't given (403)Add the host to both lists on purpose
MAIN-SANDBOX-0006runtimeThe sandbox driver is unavailable (503, retryable)Retry; check the provider's status
MAIN-SANDBOX-0007runtimeThe run would pass, or reached, its cost ceiling (402)Lower timeout, or raise maxCost on purpose
MAIN-SANDBOX-0008runtimeNo sandbox session with that id in the current tenant, or it was closed (404)Create a new session
MAIN-SANDBOX-0009runtimeA secret reference isn't under sandbox.secrets (403)List the secret under sandbox.secrets on purpose
MAIN-SANDBOX-0010checkeval, new Function or node:vm runs a value that isn't a string literalRun the code with sandbox.run
MAIN-SANDBOX-0011check, runtimeThe local sandbox driver in productionUse vercel-sandbox or e2b in production
MAIN-SANDBOX-0012checksandbox.network lists a host that network.allow doesn'tAdd the host to network.allow, or remove it from sandbox.network

I18N

Languages and formats (spec i18n, planned for 0.4).

CodeRaised byMeaningFix
MAIN-I18N-0001checkA key is missing from a required localeAdd the message, or run mainsdk i18n draft and approve it
MAIN-I18N-0002checkA locale isn't supported by the target runtime's IntlUse a runtime with full ICU, or drop the locale
MAIN-I18N-0003checkA message has a syntax error, or its variables differ from the default locale'sFix the message so it parses and uses the same variables
MAIN-I18N-0004runtimeA message was missing and a fallback was used (logged once per key and locale)Add the message in that locale
MAIN-I18N-0005runtimet() was called without a value its message needs (logged)Pass every variable the message uses
MAIN-I18N-0006checkreview: none: AI drafts reach users without review (warning)Set review: person unless you accept the risk on purpose
MAIN-I18N-0007runtimeAn agent or service tried to approve a translation draft (403)A person approves drafts
MAIN-I18N-0008checki18n.negotiate lists ip or an unknown sourceUse choice, account and header
MAIN-I18N-0009runtimeNo message for the key in any locale; production never shows the key (logged)Add the message to the default locale

VOICE

Realtime voice agents (spec ai-voice, planned for 0.6).

CodeRaised byMeaningFix
MAIN-VOICE-0001runtimeA voice session option is invalid (400)Pass one of model or pipeline, a known voice and a declared agent
MAIN-VOICE-0002runtimeThe voice driver doesn't offer this (501)Use a driver that declares the capability
MAIN-VOICE-0003runtimeRecording refused: recording off, or no consent from the caller (403)Set record: consent and record the caller's consent first
MAIN-VOICE-0004runtimeThe session reached its duration or cost limit and ended after a closing lineRaise maxDuration or the limit on purpose
MAIN-VOICE-0005runtimeA telephony or room webhook failed signature verification (401)Check the webhook secret; investigate the sender
MAIN-VOICE-0010checkA phone number routes to a voice session with no disclosureSet ai.voice.disclosure or the session's disclosure
MAIN-VOICE-0011checkA voice, telephony or room driver's hosts aren't in network.allowAllow the hosts on purpose

EVAL

Evals for AI features (spec ai-evals, planned for 0.5).

CodeRaised byMeaningFix
MAIN-EVAL-0001CLIAn eval set is invalid, or its judge model is the feature's own model (exit 2)Fix the set as the error names; pick a different judge model
MAIN-EVAL-0002CLI, checkA feature's score is below its threshold or regressed from the baseline (exit 1)Fix the prompt or model, or update the baseline on purpose
MAIN-EVAL-0003checkA prompt or model changed since the last eval result, or a feature with an eval set has noneRun mainsdk eval
MAIN-EVAL-0004checkAn eval set or exported sample holds personal dataReplace the value with a synthetic one
MAIN-EVAL-0005CLIThe eval run would pass --max-cost (exit 2)Raise --max-cost on purpose, or run one feature

Codes from other specs

These check, CLI or mixed codes are defined in a spec's Codes table and listed here automatically. The spec holds the full cause, and npx mainsdk explain <code> gives the fix.

CodeRaised byMeaningSpec
MAIN-ADOPT-0002CLIThe stack is not Next.js or Node; adopt stops and changes nothingmigration-skill
MAIN-ADOPT-0003CLIA route changes or reads data and never checks who is calling (access gap)migration-skill
MAIN-ADOPT-0004CLIThe browser queries the database directly, so row rules are the only protection (data gap)migration-skill
MAIN-ADOPT-0006CLIThere is nothing to migrate in the module, or it is not a module (secrets, auth, data, other)migration-skill
MAIN-ADOPT-0007CLIA call still sits behind an interface's raw() escape hatch; listed by finish with file and linemigration-skill
MAIN-ADOPT-0008CLIThe working tree has uncommitted changes; a module step starts from a clean treemigration-skill
MAIN-ADOPT-0009CLINo sign-in or checkout flow was found to lock, or a named flow points at text that is not theremigration-skill
MAIN-ADOPT-0010CLIA module step is still open, or verify ran with none openmigration-skill
MAIN-ADOPT-0012CLIThe folder is not a git repository, or the module branch could not be createdmigration-skill
MAIN-ADOPT-0013CLI, MCPThe name is not an adopt tool, or not an agent adopt writes a skill formigration-skill
MAIN-ADVISOR-0001checkadvisor is invalid: may empty or naming an undeclared rule, run: auto with a rule in may that has an app or people step, an unknown wake signal, or no agents.advisoradvisor
MAIN-API-0020checkCORS lets any origin call the API (*, origin: true or a bare cors())main27-baseline
MAIN-ASSURE-0001check, CLIAn exception in main.yaml for a <standard>:<control> rule has no reason, approver or expiry (400). Fix: give every exception a reason, an approver and an expiry dateassure
MAIN-ASSURE-0002CLINo standard, pack, format or run file by that name, or no standard was chosen (400). Fix: use one of the standards the message listsassure
MAIN-ASSURE-0004CLIAn evidence bundle does not verify: the signature fails, a section is missing or no public key was given (exit 1). Fix: do not rely on the bundle; run assure again on the repoassure
MAIN-ASSURE-0005CLINo mainsdk record could be read from the URL (exit 2). Fix: check the address serves /.well-known/mainsdk.json over HTTPSassure
MAIN-ASSURE-0006cloudAssigning a failure to a teammate from the console needs Teams (402, with an upgrade link). Fix: upgrade to Teams, or assign the failure in your own trackerassure
MAIN-ASSURE-0007cloudThe failure to assign is not in the account's latest run (404). Fix: assign a ref from the latest runassure
MAIN-ASSURE-0008CLI--fix could not open its pull request: git has no origin, gh is not signed in, or the tree is not clean (502). Fix: fix the git setup, or apply the listed changes by handassure
MAIN-AUTH-0012check, runtimeCheck (high): an admin role in auth.admin.roles can sign in with a method phishing can defeat while auth.admin.require isn't phishing-resistant. Runtime: auth.raw() was called (logged). Fix: set auth.admin.require: phishing-resistant, or remove the weak methods from auth.methodsauth
MAIN-AUTH-0053checkauth.risk.step-up names a method that isn't on, or only methods weaker than the ones it steps up fromauth
MAIN-AUTH-0055checkThe identity-provider driver named by auth.driver does not offer a method (its capability profile says false). High, and it fails the check, when the app uses the method; a warning otherwiseauth
MAIN-AUTH-0081clientThe person cancelled the passkey prompt, or the browser refused it (NotAllowedError or AbortError); not retryable without a new gestureauth-client
MAIN-AUTH-0082clientThe auth routes answered 404 or HTML: the adapter isn't mounted or base is wrongauth-client
MAIN-AUTH-0083clientThis browser has no WebAuthn, or no conditional mediation when mediation: "conditional" was asked forauth-client
MAIN-AUTH-0090checkA password is stored with a bare hash instead of passkeys or the auth interfacemain27-baseline
MAIN-AUTH-0091checkThe sign-in uses the OAuth implicit flow (response_type=token)main27-baseline
MAIN-AUTH-0101checkassetlinks.json or apple-app-site-association does not match the signing identity declared in targets.mobile.signing, so app links and passkeys would not bind to the appmobile-auth
MAIN-BACKUP-0001checkThe provider's best RPO (PITR step, else snapshot gap) is above backup.rpo. Fix: turn on PITR or raise backup.rpobackup-restore-evidence
MAIN-BACKUP-0002checkThe provider keeps restore points for less than backup.keep. Fix: raise the provider retention or lower backup.keepbackup-restore-evidence
MAIN-BACKUP-0003checkThe last drill took longer than backup.rto. Fix: shrink the restore path or raise backup.rto to what a drill measuredbackup-restore-evidence
MAIN-BACKUP-0006checkbackup.rpo, backup.rto, backup.keep or backup.drill is missing or not a duration. Fix: set durations such as 15m, 1h, 35dbackup-restore-evidence
MAIN-BASE-0001pack buildA point update removes a rule an earlier point had; point updates only add checksmain27-baseline
MAIN-BASE-0002contract checkAn interface outside the phase 1 stable core is marked stable without two drivers, a passing conformance suite and three production usersmain27-baseline
MAIN-BOT-0005checkA bots value is invalid: a door path that matches no route, challenge not below deny, an unknown country code or CIDR, or an unknown keybot-defence
MAIN-CACHE-0011checkcache.scope: public on an action whose risk isn't read, whose method isn't GET, or that declares a permissionhttp-cache
MAIN-CACHE-0012checkAn app-scoped cache.wrap or cache.set holds the result of a db read, which is owner or tenant datahttp-cache
MAIN-CANARY-0003checkcanaries is set but nothing is planted in that env, or a model named under records doesn't existexfiltration-guard
MAIN-CONFIG-0030checkA main.yaml key isn't in the schema; fix names the nearest key, so maxSize suggests max-size and payments suggests paycohesion
MAIN-CONFIG-0031checkA store-backed feature that must survive a restart (idempotency, meter, workflow leases) runs on a store whose profile says durable: falsecohesion
MAIN-CONFIG-0032checkA main.yaml value fails the schema: wrong type, not the one allowed constant, or not matching the key's pattern; the finding names the path. Fix: write the value in the form the finding showscohesion
MAIN-CONFIG-0033checkThe main.yaml schema isn't built, so keys and values weren't validated (low, a warning). Fix: run pnpm build in packages/sdk, which runs tools/build_main_schema.pycohesion
MAIN-CONNECTOR-0001check, runtimeA connector's settings are not usable: an unknown driver, a missing https instance or url, or auth that is not a secret:NAME referenceconnectors
MAIN-CONTEXT-0001checkcontext is invalid: no group, a purpose without a description, a field outside the built-in schema or the app's declared extras, retention over 90d, a share-with app that isn't a mutual peer, or a sink other than db or eventscontext
MAIN-CONTEXT-0006checkShared context in an app with users.audience: children, or a purpose touching a children's audience, without the purpose marked children: guardian-consent and spec privacy-lifecycle's age gate in placecontext
MAIN-CONTRACT-0001buildTwo error registry entries share a code, or a code does not match MAIN-<AREA>-<NNNN>; the message names both entrieserrors
MAIN-CONTRACT-0004CLIcontract diff --base found no contract snapshot at the given ref or fileversioned-contracts
MAIN-CRYPTO-0013checkcrypto.fips is on but crypto.module does not name the validated module, its version and certificate numberpost-quantum
MAIN-DATA-0040checkA statement takes a lock that blocks reads or writes on an existing table while it runsdb-migrations
MAIN-DATA-0041checkA rename or drop of a column or table that the base ref's code still reads, so the running release breaks during the deploydb-migrations
MAIN-DATA-0042checkA new migration for a tool that can't take a lock timeout from the runner doesn't set lock_timeout itselfdb-migrations
MAIN-DATA-0043checkAn UPDATE or DELETE with no WHERE, or a backfill of a whole table, in a migration; run it as a batched jobdb-migrations
MAIN-DATA-0044CLIA migration statement timed out waiting for a lock after every retry; nothing after it was applieddb-migrations
MAIN-DATA-0045CLIAnother instance holds the migration lock; this run waited and found every migration already applieddb-migrations
MAIN-DATA-0051checkA serverless target connects to Postgres without a pooled endpoint, so each instance opens its own connectionsdb-queries
MAIN-DATA-0055checkA db call is awaited inside a loop over the results of another querydb-queries
MAIN-DATA-0056checkA db.timeout, db.pool or db.slow value is invalid: a request timeout over 30s, a pool max over 100, or slow not under the request timeoutdb-queries
MAIN-DATA-0061checkjobs.run, events.publish, webhooks.emit, email.send or notify called inside a db.transaction callback on the module instead of on txdb-writes
MAIN-DATA-0062checkA unique index on a model with trash doesn't exclude trashed rows, so a deleted record blocks a new onedb-writes
MAIN-DATA-0065checktrash on a model with a labelled field is longer than that label's retention, or trash isn't a valid durationdb-writes
MAIN-DATA-0070checkSQL is built from strings (a template literal or concatenation)main27-baseline
MAIN-DATA-0071checkA connection string uses a shared admin account such as root, admin or postgresmain27-baseline
MAIN-DATA-0180checkA query filters, sorts or joins on the raw value of a vaulted field, which the database holds only as a token. Fix: use the driver's blind index, or look the person up by an idresidency-vaults
MAIN-DATA-0181checkThe vault driver's declared countries (vault.countries) miss a country in markets. Fix: pick a driver that supports it or drop the marketresidency-vaults
MAIN-DATA-0182checkA vaulted field has a label a vault cannot hold, such as pan. Fix: use a canonical label; never store card numbersresidency-vaults
MAIN-DEBUG-0001cloudA debug session, replay, hosted triage or inbox forwarding needs Teams (402, with an upgrade link). The app is not changed. Fix: move the project to Teamsdebug-loop
MAIN-DEBUG-0002cloudA debug session must name exactly one of user, request or release, and a duration such as 30m or 1h (422). Fix: give one target and a valid --fordebug-loop
MAIN-DEBUG-0003cloudNo debug session has that id in this project (404). Fix: list the sessions of the project and pass one of their idsdebug-loop
MAIN-DEBUG-0004cloud, CLIThe trace has no recorded request, or the project has no replay handler for its action (404). Fix: check the trace id, or export the action from mainsdk.replay.tsdebug-loop
MAIN-DEBUG-0005cloudTriage needs the GitHub app connected for this project (409). Fix: run mainsdk triage connect githubdebug-loop
MAIN-DEBUG-0006cloudTriage has not opened that issue or pull request (404). Fix: run mainsdk triage run first, then pass the number it printeddebug-loop
MAIN-DEBUG-0007cloudA report, repository or screenshot address is not valid; screenshots must be getqr.id uploads (422). Fix: upload the screenshot through getqr.id and send its linkdebug-loop
MAIN-DEPLOY-0001check, CLIA schedule can't be deployed: its expression is computed at runtime and the target has no long-running process, or jobs.schedules and a jobs.schedule call give one name two expressionsdeploy
MAIN-DEPLOY-0002check, CLIdeploy.regions names a region outside the app's data regions, or the target can't run in a data regiondeploy
MAIN-DEPLOY-0003CLIdeploy preflight found required env var names missing or empty in the build; the names are listed, never a valuedeploy
MAIN-DEPLOY-0004check, CLIA schedule or region breaks the declared platform plan's limit (for example a cron more often than daily on Vercel Hobby, or two regions on Hobby)deploy
MAIN-DEPLOY-0005check, CLIA Next.js app targets Docker or Fly without output: "standalone" in its Next.js configdeploy
MAIN-DEPLOY-0010check, CLIA generated block is stale against main.yaml, or was edited by hand; the fix is the deploy config command that rewrites itdeploy
MAIN-DEPLOY-0011check, CLIA secret would reach the image or the build log: a Dockerfile ARG or ENV named after a secret: reference, or .dockerignore not excluding .env*deploy
MAIN-DEPLOY-0012CLIdeploy diff --fail-on widen found a change that widens what the target environment may do: a new allowed host, a new secret, a new region or a looser grantdeploy
MAIN-DEPS-0001checkA direct dependency isn't on its registry: possibly a name a model made up, and anyone may register it (high)dependency-check
MAIN-DEPS-0002checkA direct dependency's first version is younger than deps.min-age (high)dependency-check
MAIN-DEPS-0003checkA direct dependency's name is one edit away from a popular package it isn't (medium)dependency-check
MAIN-DEPS-0004checkA resolved package has a known advisory; at or above advisories.fail-on it fails, below it warnsdependency-check
MAIN-DEPS-0005checkA package's licence is denied, outside a non-empty allow list, or unknown with unknown: faildependency-check
MAIN-DEPS-0006checkA package runs an install script (preinstall, install, postinstall) and isn't in deps.scripts.allow (warning)dependency-check
MAIN-DEPS-0007checkAdvisories and package ages weren't checked because the network was unavailable (info, or a failure with offline: fail)dependency-check
MAIN-DEPS-0008checkAn advisory ignore entry has expired, or has no until or reasondependency-check
MAIN-DEV-0001cliA fix, recipe or MCP write would widen a grant (network.allow, permissions, access roles, agents budgets, an exception); it is planned but not applied without --allow-widen from a person, and next returns ask-personagent-experience
MAIN-DEV-0002cliA recipe or fix doesn't apply cleanly to the current code; fix names the file and the first conflicting hunkagent-experience
MAIN-DEV-0003cliAn MCP write tool was called on a server started without --allow-writeagent-experience
MAIN-DEV-0004checkThe generated types are older than main.yaml; run mainsdk dev, sync or nextagent-experience
MAIN-DEV-0005cliAn unknown command, subcommand, flag or preset; fix names the nearest match and mainsdk help (exit 2)design-language
MAIN-DEV-0006cliinit found an existing main.yaml; fix names --new-id and --force (exit 2)design-language
MAIN-DEV-0007cliA command that reads main.yaml ran in a folder with none; fix names mainsdk init (exit 2)design-language
MAIN-DEV-0008climainsdk dev refused to start under env: prod; fix names the dev environment (exit 2)design-language
MAIN-DEV-0009climainsdk dev <entry> found no file at the entry, or no fetch function as its default export; fix names what to export (exit 2)design-language
MAIN-DEVICE-0001checkmainsdk/device is imported but main.yaml has no device section; device calls throw it at runtime (500)device-identity
MAIN-DEVICE-0002checkmain.yaml declares device but no code imports mainsdk/device; nothing is serveddevice-identity
MAIN-DEVICE-0003check, runtimeThe device section is invalid: unknown driver or key, a value out of range, authority written as a literal instead of secret:NAME, more than 2 authority keys, an oidc entry without issuer, audience or tenant, or a proof not in the list. The app doesn't startdevice-identity
MAIN-DEVICE-0004check, runtimedriver: taps without @mainsdk/device-taps installed, or an @taps/* import outside that packagedevice-identity
MAIN-DEVICE-0016checkProduction runs with no device.authority, or with the development authority key that mainsdk dev generateddevice-identity
MAIN-DEVICE-0022check, runtimeThe device.attest section is invalid: require: hardware or environment, formats, roots, builds or min-security-level with driver: local; an unknown format; a root or builds file that doesn't exist; every or grace out of rangedevice-attest
MAIN-DEVICE-0038check, runtimeThe device.telemetry section is invalid: a stream name that doesn't match the pattern, a size or rate out of range, redact that isn't a list of pathsdevice-telemetry
MAIN-DEVICE-0039checkdevice.telemetry.on names a stream that isn't declared, or a declared stream has no handlerdevice-telemetry
MAIN-DEVICE-0050check, runtimeThe device.policy section is invalid: stages that don't increase or don't end at 100%, hold outside 5m to 7d, rollback-if outside 1% to 50%, approve above 2, or an unknown tighten directiondevice-policy
MAIN-DEVICE-0066checkA client.commands.handle handler passes its input to a process or an evaluator (system.run, child_process, eval, new Function, vm, dynamic import())device-commands
MAIN-DEVICE-0067checkA command type is unsafe to declare: its input schema has an unbounded string field named command, cmd, script, code, shell, exec or args; it uses the mainsdk. prefix; it is destructive with approve: 0; or it is reaction: true while destructive, or write without undodevice-commands
MAIN-DEVICE-0071check, runtimeThe device.commands section is invalid: a value out of range, or ttl over max-ttldevice-commands
MAIN-DEVICE-0082check, runtimeThe device.heartbeat section is invalid: every outside 15s to 1h, late-after outside 2 to 10, silent-after outside 3 to 100 or not above late-afterdevice-health
MAIN-DEVICE-0092check, runtimeThe device.taps section is invalid: a did:web without a key-history log, TAPS-CS3, an unknown delegation target, or a status refresh outside 5m to 24hdevice-taps
MAIN-DEVID-0001cloud, sdkThe account in a developer record is not a GitHub login (400). Fix: run mainsdk login again to sign in with GitHubverified-developers
MAIN-DEVID-0002cloudThe identity provider answered something this version does not understand (502). Fix: try the verification again laterverified-developers
MAIN-DEVID-0003cloudThe organisation could not be verified because a check could not run (502). Fix: try the verification again laterverified-developers
MAIN-DEVID-0004cloudCertified partner is not yet available to buy (409). Fix: choose Trusted publisher, which is earned, or ask to be told when partners openverified-developers
MAIN-DEVID-0005cloudThe appeal has nothing to appeal or does not say what was fixed (409). Fix: file an appeal after a drop and say what you fixedverified-developers
MAIN-DOCS-0001CLImainsdk docs ran in an install with no bundled docs; a source checkout builds them with build_docs.py --bundledocs-versions
MAIN-DOCS-0002CLIThe installed version has no docs page with that name; the fix lists the closest pagesdocs-versions
MAIN-DRIVER-0001usageA listing, claim, revocation feed or driver path is not valid (400). Fix: run mainsdk driver publish to build the listing from a conformance rundriver-marketplace
MAIN-DRIVER-0002usageThe driver fails every contract version it claims, so there is nothing to list (422). Fix: fix the failing conformance tests with mainsdk driver test, then publish againdriver-marketplace
MAIN-DRIVER-0006checkThe app uses a driver the marketplace revoked; the warning names the driver and the advisory. The app keeps serving (fail static). Fix: move to another driver or a fixed releasedriver-marketplace
MAIN-DRIVER-0007usageThe driver is not listed (404). Fix: search with mainsdk driver search <interface>driver-marketplace
MAIN-E2E-0007check, runtimeThe post-quantum hybrid suite was asked for before spec post-quantum is in place (501)e2e
MAIN-E2E-0008checkA field in e2e.fields is read by server-side search, moderation or analytics, which skip it; e2e.accept silences ite2e
MAIN-E2E-0009check, runtimeThe driver is not for production: local in production, mls without @mainsdk/e2e-mls, or a driver whose production is false in production (500)e2e
MAIN-EJECT-0001ejectNo recipe exists for the interface, or for the driver main.yaml names; the fix lists the drivers that have oneeject
MAIN-EJECT-0002ejectNo file imports the interface, so there is nothing to ejecteject
MAIN-EMAIL-0006check, runtimeThe email section of main.yaml is invalid, names no driver, or lacks a value a call needs, such as email.unsubscribe-url (400)email-notify
MAIN-EMAIL-0009checkEmail tracks opens or clicks; reported as a warningemail-notify
MAIN-EMAIL-0010checkA real email driver in production with no email.webhook, so bounces and complaints never reach the suppression list; reported as a warningemail-notify
MAIN-EMAIL-0011checkThe source calls email.marketing with no unsubscribeemail-notify
MAIN-EXFIL-0006checkAn exfiltration value is invalid: a receiver not in network.allow or any driver's hosts, an unknown label, a bulk limit below 1, or an unknown keyexfiltration-guard
MAIN-FILES-0016checkThe configured files driver cannot meet a guarantee, named by its id in the message (a warning, so the run still passes): uploadthing declares upload-single-use and data-regionfiles-share
MAIN-FLEET-0006check, runtimeA build includes a package the fleet policy blocks (403). Fix: update or remove the packagefleet-control
MAIN-GEO-0002checkgeo.of is used in access code: in a file under a folder named access, policy, policies or auth, or its call, or a variable it was put in, sits in the arguments of auth.require, access.check, access.decide or policy.decidegeo
MAIN-GEO-0005check, runtimeA geo key is wrong (runtime: 400): an unknown driver or edge, a provider driver with no key: secret:NAME, or geo.of used with no declared edgegeo
MAIN-GO-0001checkgolangci-lint reported an issue in a Go project (the finding names the linter, the file and the line). Fix: Fix the code the linter points at, as its message says; never add a nolintgo-sdk
MAIN-GO-0002checkgosec reported a weakness in Go code. Fix: Fix the weakness gosec names; never add a #nosecgo-sdk
MAIN-GO-0003checkgovulncheck found a known vulnerability the program can reach through a function it calls (the finding names the OSV id, the module and the fixed version). Fix: Upgrade the module to the fixed version the finding namesgo-sdk
MAIN-GO-0004checkA Go check tool isn't installed, so its gate did not run (a warning, never a pass). Fix: Install it: go install golang.org/x/vuln/cmd/govulncheck@latest, and gosec and golangci-lint the same waygo-sdk
MAIN-GUARD-0001check, runtimeA rule with a people step is run: auto; or a source asked for an auto run of onereaction-safety
MAIN-GUARD-0002check, runtimeA step is on the never-a-reaction list; refused from every sourcereaction-safety
MAIN-GUARD-0005check, runtimeAn app-class step was triggered by one tenant's signals without tenant-quorum tenants and without approval; it was turned into an approvalreaction-safety
MAIN-GUARD-0008checkA guard value is outside its range, or min-prefix is set wider than /16 or /48reaction-safety
MAIN-IDENT-0001check, runtimeAn identity request asks for a claim beyond what it needs, gives no purpose, or an age gate is not a whole age from 1 to 99digital-ids
MAIN-IDENT-0005check, runtimedigital-ids in main.yaml is not valid: no wallet listed, an unknown wallet, or a request with no claims or no needdigital-ids
MAIN-KEYS-0021checkkeys.pkcs11 is incomplete or its PIN is a literal (400). Fix: set keys.pkcs11.pin to secret:HSM_PIN and name the module and keys.keyhsm-keys
MAIN-KEYS-0023checkA FIPS claim has no level or CMVP certificate, or is made on a driver that is not an HSM (400). Fix: state keys.fips from the vendor's certificate, or remove ithsm-keys
MAIN-LOG-0020checkA password, key, token or authorization value is passed to a log callmain27-baseline
MAIN-MIGRATE-0001CLImainsdk migrate <from> applied the codemods but mainsdk check or a locked flow failed, so the branch is kept and no pull request opens (400). Fix: Fix the finding on the migrate/<from> branch, then open the pull request by handmigration-guides
MAIN-MIGRATE-0002CLImainsdk migrate <from> could not start or finish: not a git repository, a working tree with changes, or a git or gh step failed (400 or 502). Fix: Commit or move your changes and run it in the app repository, or use --report-only to read the report without a branchmigration-guides
MAIN-MOBILE-0001checktargets.mobile in main.yaml is not valid (missing or malformed bundle ID, permission, signing identity or name); the finding names the keyexpo-adapter
MAIN-MOBILE-0003checkSource writes a token, secret, password or refresh value to AsyncStorage or MMKV, which are not encryptedexpo-adapter
MAIN-MOBILE-0004checkApp source calls fetch, XMLHttpRequest or axios directly instead of the SDK client, so the network allowlist, audit and attestation do not applyexpo-adapter
MAIN-NEIGHBOUR-0001checkneighbours is invalid: host: on with apps.registry: off, a share or listen name that isn't a signal name or glob, priority outside 1 to 9, max-posture: lockdown, max-for over 1h, or asks.accept with a verb outside the threeneighbours
MAIN-NEIGHBOUR-0005checkasks.accept lists posture.raise or load.shed but apps.link is off or apps.peers is emptyneighbours
MAIN-NET-0020check, runtimeA tcp://, udp:// or unix:// entry, a network.listen entry or a network.udp entry doesn't parse: no port, a port outside 1 to 65535, a range written high to low, an unknown protocol, IPv6 without brackets, a bind address that isn't an IP, or a unix path that is relative, not normalized, holds .. or * (other than a final /* in allow) or is over 104 bytes (fails at load; names the entry)net-sockets
MAIN-NET-0025check, runtimeTLS verification turned off outside dev and test, or a minimum version below TLS 1.2 anywherenet-sockets
MAIN-NET-0028check, runtimeA raw socket on a target that can't run it: net.listen, net.listenUnix or net.udp on a serverless or edge target, net.connect or net.connectUnix on an edge target, or a unix socket call on Windows; names the target, the runtime and the fallbacknet-sockets
MAIN-NET-0029checkA net.listen port or UDP bind found in the code that network.listen doesn't declarenet-sockets
MAIN-NET-0030checkA network.listen entry binds beyond loopback with no from (a warning, not a failure)net-sockets
MAIN-NET-0040checkThe code calls a non-local host over plain http://main27-baseline
MAIN-NET-0041checkTLS below 1.2 is forced, or certificate checks are turned offmain27-baseline
MAIN-NET-0050checkInfo.plist or app.json turns off App Transport Security with NSAllowsArbitraryLoads, so the app can load plain httpexpo-adapter
MAIN-NET-0051checkAndroidManifest.xml or app.json allows cleartext traffic (usesCleartextTraffic), so the app can send data over plain httpexpo-adapter
MAIN-NORMS-0001checkA norms value is invalid: every outside 1m to 15m, an unknown season, metric or time zone, learn over 28d, min-samples under 10, z under 2, or margin outside 0% to 200%norms
MAIN-NOTIFY-0001check, runtimeThe notify section of main.yaml is invalid or a provider block is missing (400)email-notify
MAIN-NOTIFY-0006check, runtimeA quiet-hours time is not HH:MM or a time zone is not a known zone (400)email-notify
MAIN-OPS-0001checkAn ops value is invalid: write: auto, a port outside 1024 to 65535, or http: on in production without ops.agent declared under agentsops-mcp
MAIN-OPS-0005climainsdk ops mcp found no running app with an ops socket for the given folder or projectops-mcp
MAIN-PACK-0001configA pack is not a pack@1 bundle: missing id or version, or not valid JSON (400). Fix: rebuild it with mainsdk pack buildindustry-packs
MAIN-PACK-0002configA pack would weaken the baseline: a permit policy, or a label rule that is not a refusal, a requirement or a restriction (400). Fix: packs add forbid policies and tightening rules onlyindustry-packs
MAIN-PACK-0003configA pack defines a label that is not canonical (400). Fix: use personal, sensitive, child, phi or panindustry-packs
MAIN-PACK-0004configA standard has no pinned version, or a control has no SCF mapping (400). Fix: write standard: pci-dss-4.0.1 and scf: <id>industry-packs
MAIN-PACK-0005configA pack policy is not valid Cedar (400). Fix: fix the syntax and rebuild the packindustry-packs
MAIN-PACK-0006configA control names a check that does not exist (400). Fix: use one of the check kinds the pack reference listsindustry-packs
MAIN-PACK-0008checkindustry names a pack that is not in the verified cache or in packs/, or whose bundle does not verify; the last good version stays in force (400). Fix: run mainsdk sync to fetch the signed packindustry-packs
MAIN-PACK-0009usageassure --standard or pack build was run without its value (400). Fix: pass the standard or the folderindustry-packs
MAIN-PACK-0010checkA field has a label the pack refuses in any store, such as pan in the payments pack (400). Fix: the mapped fix, for payments "use hosted fields"industry-packs
MAIN-PACK-0011checkA field the pack needs encrypted is not, so reads cannot be audited (400). Fix: set db.fields.<field>.encrypt to trueindustry-packs
MAIN-PACK-0012checkA driver that can hold regulated data declares no signed business associate agreement (400). Fix: use a driver whose manifest declares baa: trueindustry-packs
MAIN-PACK-0013checkThe pack does not allow the driver in use for an interface (400). Fix: use one of the drivers the pack listsindustry-packs
MAIN-PACK-0014checkAudit logs are kept for less time than the pack needs (400). Fix: set logging.retentionindustry-packs
MAIN-PACK-0015checkAdmin access does not require multi-factor authentication (400). Fix: set auth.admin.require to phishing-resistantindustry-packs
MAIN-PACK-0020checkA third-party provider is used that the pack's provider register does not list (400). Fix: add it to compliance.providers with its reason and ownerindustry-packs
MAIN-PACK-0022checkChange control is not switched on, so releases are not reviewed (400). Fix: set compliance.change-control and require a reviewed pull requestindustry-packs
MAIN-PACK-0023checkNo passing restore drill inside the pack's window (400). Fix: run mainsdk drill restore --to scratch and keep the signed evidenceindustry-packs
MAIN-PERM-0008checkA disk value is invalid: a max or reserve that isn't a size or a percentage, a reserve over 50%, or temp set to a folderapp-permissions
MAIN-PLAT-0001checkA Tauri or Electron release build is unsigned, or its updater has no public key or uses plain httpplatforms
MAIN-PLAT-0002checkA browser extension is not Manifest V3, asks for a broad host permission with no declared need under platforms.extension.needs, or its CSP allows eval or remote scriptsplatforms
MAIN-PLAY-0001playground, cliThe tests file is not a list of tests with a name, an input and allow or deny as the expectation (400). Fix: write each test as { "name": "…", "input": { … }, "expect": "allow" }policy-playground
MAIN-PLAY-0002playground, cliThe replay holds more recorded decisions than the playground replays at once (413). Fix: replay a smaller sample of at most 100000 decisionspolicy-playground
MAIN-PLAY-0003playgroundThe link does not hold a playground state this version can read (400). Fix: ask for the link again, or paste the policy and request in by handpolicy-playground
MAIN-PLAY-0004playgroundThe state is too large to share, or getqr.id did not make the link (502 or 413). Fix: share without the replay, or share again when the connection is backpolicy-playground
MAIN-PLAY-0005climainsdk policy play could not read a policy, request, entities, tests or replay file (400). Fix: pass a folder with policies and a request file that holds JSONpolicy-playground
MAIN-PLAYBOOK-0001checkA playbooks or posture value is invalid: an unknown step, preset, trust level or severity; a for over 24h; a count window under 1m; a cooldown under 1m; or a parameter that doesn't fit the stepplaybooks
MAIN-PLAYBOOK-0002checkA step's interface isn't configured or built (for example bots.block with no bots section, workers.scale before parallelism); fix names the specplaybooks
MAIN-PLAYBOOK-0003check, runtimeA step would not tighten: limits.tighten to a larger amount or another period, a flag that isn't defined, an agent that isn't declared; refused before anything runsplaybooks
MAIN-PLAYBOOK-0010checkAn action used as a step isn't marked reaction: true, or its undo names an action that doesn't existplaybooks
MAIN-POLICY-0007testmainsdk test policy --recorded was given a folder that does not existpolicy
MAIN-PRIV-0001checkA data label in use has no retention rule (privacy.retention.<label>)privacy-lifecycle
MAIN-PRIV-0004checkThe privacy section of main.yaml does not read: an unknown key, a retention that is not a duration, or retries out of rangeprivacy-lifecycle
MAIN-PYTHON-0001checkRuff reported a rule in a Python project (the finding names the rule, the file and the line). Fix: Fix the code the rule points at, as its message says; never ignore the rulepython-sdk
MAIN-PYTHON-0002checkPyright reported a type error in strict mode. Fix: Fix the type error where it is reported; never add a type: ignorepython-sdk
MAIN-PYTHON-0003checkBandit reported a weakness in Python code. Fix: Fix the weakness Bandit names, using its more_info pagepython-sdk
MAIN-PYTHON-0004checkA Python check tool isn't installed, so its gate did not run (a warning, never a pass). Fix: Install it: pip install ruff pyright banditpython-sdk
MAIN-REPORT-0005checklogging.errors is invalid: sentry with no dsn, a dsn host not in network.allow, a sample outside 0 to 1, or alert.spike.over under 1error-reporting
MAIN-RUST-0001checkClippy reported a lint in a Rust project (the finding names the lint, the file and the line). Fix: Fix the code the lint points at, as its message says; never allow the lint awayrust-sdk
MAIN-RUST-0002checkcargo-audit found a dependency with a known advisory (the finding names the advisory and the crate). Fix: Upgrade the crate to the patched version the advisory namesrust-sdk
MAIN-RUST-0003checkcargo-deny refused a dependency for its licence, a ban, its source or an advisory. Fix: Replace the dependency, or change deny.toml with the owner's approvalrust-sdk
MAIN-RUST-0004checkA Rust check tool isn't installed, so its gate did not run (a warning, never a pass). Fix: Install it: rustup component add clippy, cargo install cargo-audit cargo-denyrust-sdk
MAIN-SANITIZE-0003checkA raw HTML sink (dangerouslySetInnerHTML, innerHTML, outerHTML, insertAdjacentHTML, document.write, v-html, {@html}) is fed by a value that doesn't come from sanitize.html or sanitize.markdownsanitize
MAIN-SECRET-0011check, runtimeA secret is past its max-age (fails mainsdk check --env <env> when the driver can report ages; a Main 27 exception covers it)secret-rotation
MAIN-SECRET-0014checkA secrets.rotation value is invalid: a bad duration, overlap longer than max-age, generate under 16 bytes, or a name the app doesn't referencesecret-rotation
MAIN-SECURITY-0001checkA security value is invalid: an unknown severity, sink or detector, or a detector threshold below 2security-events
MAIN-SECURITY-0002checkto includes otel and a region the app stores data in has no endpoint (no regions.<r> and no telemetry.otel)security-events
MAIN-SESSION-0001checkA token is written to localStorage or sessionStoragemain27-baseline
MAIN-SESSION-0002checkA token is issued for longer than seven daysmain27-baseline
MAIN-SIGNAL-0006checkA signals value is invalid: keep outside 100 to 10,000, a TTL over ttl.max or over 24h, or key written as a literal instead of secret:NAMEsignals
MAIN-SIGNAL-0007checkProduction uses a shared broadcast driver (redis) and app-scope signals, with no signals.key; another app on the same store could forge themsignals
MAIN-SIM-0001testAn injection or option needs a spec that has no code yet (attack, key, approve without playbooks); the message names the specintelligence-sim
MAIN-SIM-0002testA sim input is invalid: an unknown app name, a start that is not a time, or a step that is not positiveintelligence-sim
MAIN-SUPPLY-0001checkA dependency is *, latest, empty or fetched from a URL or gitmain27-baseline
MAIN-SYNC-0007checkA table under sync.tables has no whole-number version, or a conflicts value that is not last-writer-wins, server-wins or action:<name>sync
MAIN-TEAMS-0001cloudThe member's role does not allow this in the organisation (403). Fix: ask an admin of the organisation to change your role or to do it for youteams-plan
MAIN-TEAMS-0002cloudThe invite is unknown, used, past its seven days or sent to another email (410). Fix: ask an admin to invite you againteams-plan
MAIN-TEAMS-0003cloudAn add-on applies only to the projects of the buyer's own organisation, and none may offer what Fleet is for (403). Fix: buy it for a project your organisation ownsteams-plan
MAIN-TEAMS-0004cloudThere is no such add-on, or it has no price yet (404 or 409). Fix: choose an add-on that is on saleteams-plan
MAIN-TEAMS-0005cloudAn annual invoice needs a purchase order number (400). Fix: pass the purchase order number of your finance teamteams-plan
MAIN-TEAMS-0006cloudThe sign-in or SCIM request is not allowed: no code, or the person is not provisioned (400 or 403). Fix: assign the person to the MainSDK application in the identity providerteams-plan
MAIN-TEAMS-0007cloudThe organisation is not an approved startup (403). Fix: apply for the startup programme and wait for the approvalteams-plan
MAIN-TEAMS-0008cloudThe evidence built for a project names another project (500). Fix: build the evidence again for the project it is pushed forteams-plan
MAIN-TEAMS-0009cloudThe project to transfer is not owned by the organisation giving it away (404). Fix: transfer a project your organisation ownsteams-plan
MAIN-UPDATE-0003checkThe updates section is invalid: a version that isn't dotted numbers, a rollout outside 0 to 100, a channel other than stable or beta, or a deprecation without a path and a sunset dateupdates
MAIN-UPDATE-0004checkupdates.min-version is above the stable channel's version, so every current client would be blockedupdates
MAIN-UPGRADE-0001CLIThe git working tree has uncommitted changes, or the folder isn't a git repository; nothing was changedupgrade
MAIN-UPGRADE-0002CLI, checkMainSDK packages are at different versions in the workspace; they move only togetherupgrade
MAIN-UPGRADE-0003CLIA codemod couldn't run (no typescript in the app, or a file didn't parse); it is listed as a manual step with file and lineupgrade
MAIN-UPGRADE-0004CLIThe registry couldn't be reached, so the target version is unknown; nothing was changedupgrade
MAIN-UPGRADE-0005CLI, checkA release marked security is newer than the installed versionupgrade
MAIN-UPGRADE-0006CLIAfter the upgrade, the install, sync, check or the app's tests failed; the branch is kept and the pull request is a draft listing the failuresupgrade
MAIN-UPGRADE-0010toolsA release's API report has a removed or changed export with no upgrade note entry, or an entry's codemod has no fixtureupgrade
MAIN-VAULT-0006configai.redact.driver is unknown, or agentcloak has no client (500). Fix: set built-in or agentcloak and pass the clientresidency-vaults
MAIN-VERIFY-0004check, runtimeA market requires an identity level its driver cannot reach, or no driver serves it (check); an identity call asked for a level above the driver's reach (runtime, 422)verify
MAIN-VERIFY-0006check, runtimeThe verify section is not valid, a driver is not built, or an email check has no app origin, share or email (500)verify
MAIN-WEB-0001checkOpen CORS: origins contains * with credentials: true (any env), or * at all with --env prodinbound-protection
MAIN-WEB-0003checkAn inbound value is invalid: a bad origin or host, a bad duration, a route pattern that matches nothing, or an unknown keyinbound-protection
MAIN-WEB-0007checkThe CSP allows 'unsafe-inline' or 'unsafe-eval' in script, or *, http: or https: alone as a script sourceinbound-protection
MAIN-WEB-0009checkCode sets a cookie with SameSite=None without Secure, or httpOnly: false for a cookie not in cookies.readableinbound-protection
MAIN-WEB-0010checksecurity-txt has no contact, or expires is missing, in the past, or more than one year after the build dateinbound-protection
MAIN-WEB-0011checkNo security-txt in a production app (a warning, not a failure)inbound-protection
MAIN-WORKER-0001checknode:worker_threads, node:cluster or child_process.fork used outside the SDKparallelism
MAIN-WORKER-0009checkA workers or cluster value is invalid: a size, processes or queue out of range, a memory that isn't a size, a module glob that matches no file, a module in two pools, or an env name that is a secret's nameparallelism
MAIN-WORKER-0010checkWorkers or cluster on a target that can't run them: cluster with more than one process on serverless, edge or Deno fails; workers on a runtime without threads warn that tasks run inlineparallelism
MAIN-WORKER-0016checkA worker module or cluster.run found in the code that main.yaml doesn't declareparallelism

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet