Skip to content
Air-Cloud docs

Rules and error codes

Every refusal carries a code, and the code is the contract: act on the code and its details, never on the message text. aircloud check and the release pipeline report the same rule ids; a release, a release part or an activation carries a deploy code; a product host answers its end users with a data-plane code.

Rules (aircloud check, and a release refused for its grammar)

rule phase message
toml.syntax validate file is not valid TOML
grammar.unsupported validate aircloud.toml declares a grammar version this platform does not support
schema.required validate a required key is missing
schema.unknown_key validate a key the grammar does not define
schema.type validate a value has the wrong type
schema.pattern validate a value does not match its grammar pattern
schema.enum validate a value is not one of the allowed values
schema.range validate a number or length is outside its allowed range
schema.shape validate a value does not satisfy a conditional or one-of rule of its kind
layout.root_missing validate aircloud.toml is missing at the repository root
layout.unknown_entry validate a file or directory inside a grammar-owned root that the layout does not define
layout.declaration_missing validate a workload directory lacks its declaration file
layout.reserved_kind validate a reserved position is not built yet
identity.name validate a directory or file name is not a valid identifier for its kind
function.entry_missing validate the function's build entry does not exist
function.component_missing validate a component listed by a function does not exist under lib/
function.trigger_entity_unbound validate an event trigger's entity selector is set on a source or topic whose events are not about a record of an entity
function.trigger_entity_missing validate an event trigger selects an entity that is not declared or is tombstoned
component.entry_missing validate the component's build entry does not exist
migration.entry_missing validate the data migration's build entry does not exist
container.dockerfile_missing validate the container's Dockerfile does not exist
site.static_tailwind validate a site with no build step cannot use Tailwind (it needs the build)
route.overlap validate two route prefixes are equal or one is a path-segment prefix of the other
route.target_missing validate a route names a function or container that does not exist
route.reserved_path validate a route prefix lies under a platform-reserved path (/.well-known/, /_air/)
route.reserved_target validate a route targets a kind that is not built yet
authenticate.sign_in_invalid validate the [authenticate] sign_in route is not reachable without a session (inside the block, or a platform-reserved path other than the hosted sign-in)
authenticate.site_without_site validate an [authenticate] route guards site pages, but the product has no site
authenticate.role_undeclared validate a default_roles or [[authenticate.route]] roles key is absent from [authenticate] roles
authenticate.default_not_below_admin validate [authenticate] default_org_path is not strictly below admin_org_path (the first admin must be able to manage self-registered end users)
secret.used_by_missing validate a secret's used_by names a workload that does not exist
secret.undeclared validate a container references a secret config/secrets.toml does not declare for it
secret.egress_without_function validate a secret declares egress hosts but no function uses it
env.overlay_unknown validate an environment overlay names an environment that does not exist
env.overlay_reserved validate an overlay names a platform-owned environment (ci, ci-*)
env.overlay_target_missing validate an overlay configures a function or container that does not exist
schema.relation_target_missing validate a relation field targets an entity that is not declared or is tombstoned
schema.owner_field_missing validate an entity's owner names no live field of the entity
schema.owner_field_type validate an entity's owner names a field that is not of type string (it holds the owning end user's sub, one line)
schema.owner_role_undeclared validate an owner_bypass_roles key is absent from [authenticate] roles
schema.owner_shared validate an entity declares both owner and shared = true: a shared record's owner is an end user of an ancestor node, so no reader below could ever be its owner
schema.enum_values_invalid validate an enum field's value lists are inconsistent: a value both live and removed, a display name for an undeclared value, or more declared values than the Flex cap
schema.default_invalid validate a field default is not a value the field accepts: a literal its type refuses, a TOML value with no JSON equivalent, an enum default that is not a live value, or a generator that is unknown, malformed or of another type
schema.default_not_allowed validate a field that takes no default declares one: a relation, file or vector field, or the entity's owner field
seed.entity_missing validate a seed or fixture file names an entity that is not declared
seed.field_unknown validate a seed record sets a field its entity does not declare
seed.relation_key_missing validate a seed relation value names a record key the same seed set does not define
agents.stale validate AGENTS.md differs from the agent map the grammar renders; regenerate it
generate.static_tailwind generate a static site cannot use Tailwind
generate.conflict generate a path the generator would create already exists (use --force to overwrite)
generate.site_exists generate the product already has a site
generate.reserved_kind generate the generator targets a kind that is not built yet
generate.bad_field generate a field argument does not match <name>:<type>[:<arg>][:required]
generate.bad_option generate an option value or combination is not allowed
generate.bad_name generate a generator's <name> is not a valid identifier for its kind (checked before anything is written)
generate.locale_untranslated generate the product declares a locale the generators have no texts for; they never write another language in its place
destroy.referenced generate another declaration still references what destroy would remove
test.target_missing validate a test/functions|components|migrations/<name>/ directory names no such workload
test.principal_role_unknown validate a test principal names a role that is not a key of [authenticate] roles
test.principal_without_authentication validate test/principals.toml declares a principal but the product declares no [authenticate] block
test.principal_unknown validate an integration step acts as a principal test/principals.toml does not declare
test.principal_profile_undeclared validate a test principal's grant names a profile that config/profiles.toml does not declare
test.principal_grant_outside_home validate a test principal's grant is placed at a node that is not at or below the principal's org node
migration.duplicate_timestamp validate two data migrations share a timestamp
seed.environment_unknown validate a db/seeds/<environment>/ directory names an environment that does not exist
seed.environment_reserved validate a db/seeds/ci/ or db/seeds/ci-*/ directory (platform-owned environments are seeded from test/fixtures/)
seed.tombstoned validate a seed record targets a tombstoned entity or sets a tombstoned field
seed.value_type validate a seed value's type is not admissible for its field type
seed.required_missing validate a seed record lacks a required field
i18n.config_invalid validate aircloud.toml [i18n] or time_zone is malformed: an unsupported locale id or zone, a default_locale outside available_locales, a fallback chain naming an unavailable locale, or a cycle
i18n.locale_file_invalid validate a locale file is not the safe YAML subset, has a top-level key other than its locale, or names a locale outside available_locales
i18n.key_duplicate validate a translation key is defined twice for one locale, or a default-locale activemodel name duplicates the display_name that carries it
i18n.key_missing validate a product translation key is missing from an available locale after its declared fallback entries
i18n.inline_text validate a site source writes user-visible text (JSX text, or a placeholder, title, aria-label, alt or label value) as a literal instead of reading it from config/locales; an aircloud-allow-inline: <reason> comment opts its line and the next out
site.entry_invalid validate a file of another kind inside a fixed-meaning app/site/src/ directory
site.resource_unrouted validate a resource page names an entity no route maps to its CRUD function
site.layout_missing validate a page or option names a layout that does not exist
csp.policy_invalid validate config/content_security_policy.toml holds a malformed directive, source expression or key, or a nonce declaration its policy conflicts with
csp.unsafe_script validate 'unsafe-inline' or 'unsafe-eval' in the effective script source list without the matching opt-in
permissions.policy_invalid validate config/permissions_policy.toml holds a malformed allowlist
i18n.inflection_unportable validate an inflection rule pattern is outside the subset every runtime reads alike (Rust regex, JavaScript iu RegExp, RE2)
i18n.currency_unit_declared validate a locale file declares number.currency.format.unit: the currency is the product's, declared once as aircloud.toml [i18n] currency, and each locale renders its CLDR symbol (ADR-255)
i18n.currency_undeclared validate code formats a currency without its own unit and aircloud.toml declares no [i18n] currency: no currency is assumed (ADR-255)
cargo.lock_missing validate a Rust crate (function, shared component or data migration) has no committed Cargo.lock beside its Cargo.toml
layout.wit_reserved validate a wit inside a function or data migration that is not the link aircloud test prepare makes: the name is reserved for the platform's guest contract, which a release never carries
site.boot_invalid validate app/site/src/main.jsx is not the boot module: side-effect imports only, the platform's CSP nonce stamp first
schema.write_role_undeclared validate a write_roles key is absent from [authenticate] roles
route.org_path_required validate a public [[route]] declares no org_path: a route with no end user acts at a declared node, never a default — write org_path = "/" to act at the tenant root
route.org_path_not_invocation validate a [[route]] that targets a container declares org_path: a container route runs no invocation, so no node acts and the platform would ignore the declaration — remove org_path
trigger.org_path_required validate an event or cron trigger declares no org_path: an invocation with no end user acts at a declared node, never a default — write org_path = "/" to act at the tenant root
elevate.entity_missing validate an [[elevate]] entity is not a live entity of db/schema
elevate.op_invalid validate an [[elevate]] op is not one of count, sum, min, max, avg, or a sum, min, max or avg has no value field its type admits
elevate.field_identifier validate an [[elevate]] filter, group_by or value field is identifying (the record id, the entity's owner field, or a unique or natural-key field): an elevated aggregate never names a record or an owner
elevate.field_unknown validate an [[elevate]] filter, group_by or value field is not a field the entity declares (the record id is elevate.field_identifier's)
elevate.scope_invalid validate an [[elevate]] scope is not node or subtree
org.operation_unknown validate an [org] operations entry is not a tree operation the capability registry publishes (contracts/capability/v1/capabilities.json)
profile.role_undeclared validate a config/profiles.toml profile names a role absent from [authenticate] roles
workspaces.profile_undeclared validate [authenticate.workspaces] admin_profile is not a profile of config/profiles.toml
workspaces.parent_not_below_admin validate [authenticate.workspaces] parent is not at or below [authenticate] admin_org_path
workspaces.parent_nests_default validate [authenticate.workspaces] parent is at or below [authenticate] default_org_path: a workspace membership would nest inside the signer's personal membership
workspaces.parent_too_deep validate [authenticate.workspaces] parent is at the org-path max_depth: no child node can be created under it
workspaces.seed_undeclared validate [authenticate.workspaces] seed names a node seed template the release does not carry (db/seeds/<environment>/nodes/<template>/)
schema.policy_invalid validate a db/schema [[policy]] rule is outside the field-policy grammar: an unknown key, effect, reference namespace, operator or combinator, a field the entity does not declare, an op its field type refuses, or a depth or size cap exceeded
authenticate.route_at_required validate an [[authenticate.route]] without at requires a role of the [authenticate.workspaces] admin_profile: a route admitting staff by such a role must be scoped to the staff's node with at
org.path_undeclared validate an org_path (a public [[route]], an event or cron trigger, an [mcp] facet) or an [[authenticate.route]] at names a node no production activation creates: it is neither the root /, a node of the [authenticate] posture (admin_org_path, default_org_path, the [authenticate.workspaces] parent, nodes) nor an ancestor of one, nor strictly below the workspaces parent, the one parent whose children are created at run time (by workspace signup, or by a function's nodes.create inside a workspace) — a node a function creates anywhere else is not declared by that code: add the node to [authenticate] nodes = [...] so each production activation creates it, or name a declared node

Deploy codes (releases, release parts, activations and the deploy API)

code meaning remedy
source_stage_failed The release's git source could not be staged (the repository or ref could not be fetched and packaged). Check the repository URL, the ref and the git credential, then create the release again.
source_entry_refused The source tree carries an entry that is not a regular file or a directory (a symbolic link, a hard link, a special file). Remove the entry from the product source.
source_artifact_invalid The uploaded source artifact does not carry exactly one product source layer of the expected media type. Upload the source with aircloud release create.
source_too_large The product source exceeds the upload size limit. Remove what the product does not need from the source.
source_invalid The product source is not a readable product tarball. Upload the source with aircloud release create.
grammar_violation The product tree breaks the product grammar; the violations are listed. Fix what aircloud check reports.
product_slug_mismatch The tree declares a different product than the one the release was created for. Create the release for the product aircloud.toml declares, or fix its slug.
inflection_pattern_unportable A product inflection rule uses a pattern the platform's runtimes would read differently. Rewrite the inflection rule with a portable pattern.
locale_bundle_uncompilable The product's locale files do not compile into a locale bundle. Fix the locale files under config/locales/.
resource_projection_failed The product schema does not project into the resource projection. Fix the schema under db/schema/.
part_build_failed A part of the release failed to build; the part and its own error are named. Fix what the part's error names.
part_not_buildable A part the release scheduled has nothing to build (the release declares no such part, or no source is staged). Create the release again; if it recurs, report it.
render_failed The build job of a part could not be prepared from the release. Create the release again; if it recurs, report it.
aot_failed The ahead-of-time compile of a data migration's component failed. Check the migration builds and runs in its unit tests, then create the release again.
build_job_lost A part's build job ended without writing its result. Create the release again; if it recurs, report it.
part_build_cancelled Another part of the release failed to build, so this part's build was cancelled; the release names the part that failed. Fix the part that failed, then create the release again.
tenant_deprovisioned The product was deleted while this release work was in flight, so the work was stopped. Nothing: the product no longer exists.
build_failed A part's build failed outside a named refusal; the message carries the build's reason. Read the message; fix the build and create the release again.
build_input_upstream_unhealthy A container's build could not pull a base image: the platform's registry proxy-cache did not serve it (the message names the proxy, the upstream and the base). The platform caches the bases of every upstream it fronts, and a base it cannot serve is usually an upstream the proxy currently cannot reach, or a tag or digest the upstream does not publish. Create the release again later; if it recurs, check that the base the message names exists upstream, pin it by digest, and report it.
build_capacity_exhausted A build waited on the account's build capacity — the releases it builds at once (deploy.build.concurrent) or the parts of one release that build at once (deploy.build.parallelism) — and the builds holding that capacity ran past their own declared deadlines, so the wait ended (ADR-280). quota names the meter, the grain, the limit and its use. A build that only waits behind others that are still within their deadlines is never refused: its part shows at_capacity while it waits. Wait for the builds already running to finish, then create the release again; to build more at once, move the account to a plan with a higher build capacity or add a build capacity add-on.
build_capacity_unavailable A build waited on the platform's build host — the build slots every account shares — and the builds holding them ran past their own declared deadlines, so the wait ended (ADR-280). It is the platform's capacity, not the account's plan: no limit of the account was exceeded. Create the release again later; if it recurs, report it.
verification_deadline_exceeds_plan The verification deadline the release derives from the test layers it declares (contracts/deploy/v1/release-deadline.json: setup, plus each declared layer's base and per-item cost) exceeds what the account's plan sells for one release (the declared meter deploy.release.verification_seconds). It is refused before anything is uploaded or built (the upload's admission), or at resolve when the source was a git repository or the plan narrowed after the upload; quota names the meter, the grain, reason exceeds_limit, the limit and the deadline derived (used), both in seconds. Declare fewer integration scenarios or system spec files (or fold several into one), or move the account to a plan with a longer verification allowance; then create the release again.
site_bundle_missing At activation, the release's published site bundle is not in the registry. Create the release again; if it recurs, report it.
instantiation_failed A function of the release does not instantiate on the functions host. Fix the function so it builds and runs in its unit tests.
part_not_built At activation, a function, container, data migration or the site has no built part. Activate a release whose build completed.
host_label_too_long The product host the environment composes exceeds one DNS label. Shorten the product slug or the environment name.
route_table_too_large The product's route table exceeds what the data plane carries. Reduce the routes in config/routes.toml.
secret_inject_undeclared A secret declares egress without declaring how it is injected. Declare the injection in config/secrets.toml.
secret_header_undeclared A secret is injected as a header without naming the header. Name the header in config/secrets.toml.
credential_name_taken A registered integration already holds the secret's name in that scope. Rename the secret, or retire the integration holding the name.
secret_unset Declared secrets have no value in the environment's scope. Set them with aircloud secrets set.
container_build_failed A container of the release failed to build. Fix the container's Dockerfile or source.
container_deploy_failed A container of the release failed to deploy. Check the container starts and serves its declared port.
migration_failed A data migration refused its run; the detail carries its error. Fix the migration.
migration_refused The functions host refused a data migration run without naming a code. Read the detail; fix the migration.
flex.schema_refused The data plane refused the schema without naming a code. Read the detail; fix the schema under db/schema/.
flex.seed_refused The data plane refused a fixture record without naming a code. Read the detail; fix the record under test/fixtures/.
release_not_eligible The release cannot be activated in that environment (not built, or not verified for production). Activate a release that is eligible there.
release_unfunded The product's account cannot fund what a release of this product spends: its verification environment, the schema changes converged twice (once in verification, once on promotion), its Apps and their databases, and the fixture records verification loads. The upload is refused before its source is stored or anything is built, so the release does not fail midway through verification. The refusal lists every shortfall: for a metered action, the units the release needs and the balance the account holds; for a count limit (entities, or one entity's records), the count the release reaches and the limit. For each metered action, add credit or move the account to a plan that includes at least the units needed; for each count limit, move the account to a plan whose limit covers the count, or declare fewer entities or fixture records. Then create the release again.
tenant_not_active The account is not active, so nothing can be activated and no git credential can be registered. Bring the account back into good standing.
environment_not_found The environment does not exist. Name an existing environment.
activation_in_flight Another activation of that environment is in progress. Wait for it to finish, then try again.
verification_failed The release pipeline did not verify the release (its tests failed, or the run errored); the verdict and the cause are carried. Read the cause; fix the tests or the product.
auto_promotion_failed The verified release could not be promoted to production automatically; the detail carries why. Promote it with aircloud release promote once the cause is resolved.
pipeline_deadline_exceeded The release pipeline ran past its deadline. Shorten the test run, then create the release again.
activation_refused The pipeline could not activate the release in its test environment; the cause names the refusal. Resolve the named refusal.
activation_failed The release's activation in the pipeline's test environment failed. Read the cause; fix what the activation reports.
activation_abandoned The release left the pipeline (it concluded failed, or was superseded) before its activation ran, so the activation was ended without touching any plane. Create a new release.
fixtures_invalid The test fixtures cannot be loaded in order (their references form a cycle). Break the cycle in test/fixtures/.
fixtures_refused The data plane refused a test fixture record; the cause names its code. Fix the record under test/fixtures/.
build.lockfile_missing package.json declares dependencies and there is no package-lock.json (only npm's lockfile is accepted). Commit package-lock.json.
build.lockfile_entry_untrusted A lockfile entry has no integrity, or its integrity carries no sha512 hash (DX59: sha1 cannot anchor trust), or it resolves outside the registry (git+, file:, a link, a tarball URL, another host); or the package carries npm-shrinkwrap.json; or the lockfile is older than v2. Regenerate the lockfile against registry.npmjs.org with npm 7 or later.
build.integrity_mismatch npm ci found a tarball whose hash differs from the lockfile's integrity. Investigate: the lockfile is the trust anchor.
build.cargo_lock_missing A Rust crate (a function, shared component or data migration) has no Cargo.lock; the build compiles a crate only from its committed lock (cargo --locked). Run cargo generate-lockfile in the crate and commit Cargo.lock.
build.cargo_lock_entry_untrusted A Cargo.lock entry is neither a crate of the product (a path package) nor a crates.io package with its sha256 checksum: a git source, another registry, or a registry entry without a checksum. The detail names the entry. Depend on crates.io releases (or on a crate of the product by path) and regenerate Cargo.lock.
build.cargo_lock_out_of_sync Cargo.toml and Cargo.lock disagree: cargo --locked would have to change the lock. Run cargo update (or cargo generate-lockfile) in the crate and commit Cargo.lock.
build.wit_supplied A Rust function or data migration crate carries a wit (a directory, file or link at <crate>/wit). The guest contract a Rust crate binds is the platform's: the build places the tree of the crate's world at <crate>/wit before cargo runs, so a tree of the product's own is refused rather than replaced (ADR-281); the path names it. Delete the named wit and create the release again. For a local build, aircloud test prepare links it to the CLI's copy of the contract, and the source-ignore rule keeps that link out of a commit and of a release.
build.lockfile_out_of_sync package.json and package-lock.json disagree (npm ci refuses to install). Run npm install and commit the lockfile.
build.engine_unsupported A package's engines.node excludes the builder's node. The platform npm config sets engine-strict (DX134), so npm refuses instead of silently skipping an optional native binding; the detail names the package, the required range and the builder node. Admit the platform's node (versions.json .node) in the package's engines.node, or pin a dependency version whose engines admit it.
build.install_script_unreviewed A dependency has an install script (preinstall, install, postinstall) that the package's package.json allowScripts neither approves nor denies. The builders' npm runs with strict-allow-scripts, so npm refuses before installing anything instead of running (npm 11) or skipping (npm 12) the script with a warning; the detail names each package and its script. Review each named script in package.json allowScripts: true runs it, false skips it (npm install-scripts approve|deny writes the entry).
build.component_missing A JavaScript function lists a shared component in its function.toml components and the product has no lib/<name>/ directory for it, so the builder cannot link it where the function's imports resolve; the path is the function's function.toml and the detail names the function and the component. Generate the component (aircloud generate component <name>) or remove it from the function's components.
build.component_link_conflict A function lists a shared component whose name an installed npm package already holds in the node_modules the component must be linked into (the function's, or the test layer's), so the import would be ambiguous; the path is the function's function.toml and the detail names the component and the node_modules entry. Rename the component, or remove the dependency of the same name from the package.json that installs it.
build.bundle_failed A JavaScript function's bundle step (esbuild) reported an error, such as an import that does not resolve; the message carries the build's reason and log_tail the end of what the build printed, where esbuild's [ERROR] lines name the file and the import. Read log_tail; fix the import or the source it names, then create the release again.
build.compile_failed A Rust function's crate did not compile (cargo reported error[E…] or could not compile); the message carries the build's reason and log_tail the end of what cargo printed, with the error and its location. Read log_tail; fix the error cargo names (cargo build reproduces it locally), then create the release again.
build.unit_tests_failed The product's unit layer failed: its test:unit (run once per release in the tests part, beside every JavaScript workload package), a Rust workload crate's cargo test (in the tests part; the path names the crate), or its site unit tests (test:site, in the site part); or the product has JavaScript unit tests but no test/package.json. The refusal carries layer unit. Fix the test or the code.
build.site_build_failed The site's build command failed; the detail carries its output. Fix the build or app/site/site.toml.
build.site_output_missing The site build produced no output directory, or an empty one. Fix the build or the output directory in app/site/site.toml.
build.site_output_invalid The site's output directory escapes app/site/ or contains a symbolic link. Keep the output inside app/site/ and free of symbolic links.
build.site_inputs_too_large The release's resource projection and locale bundle exceed what a site build carries. Reduce the declared resources or translations the site receives.
build.test_inputs_too_large The release's locale bundle exceeds what the tests part carries to the unit tests. Reduce the product's translations.
site_publish.entry_invalid The built site bundle holds an entry that is not a regular file or a directory (a symbolic link, a hard link, a device). Make the site build write regular files only.
site_publish.reserved_path A site file lives under a path the platform reserves (ADR-214: public/.well-known/, public/_air/). Move the file out of the reserved path.
slug_invalid The product slug is outside the grammar (lowercase words joined by single hyphens, at most 30 characters). Choose a slug that follows the grammar.
slug_taken Another product already holds that slug. Choose another slug.
tenant_owner_required The product would have no owner. Every product has exactly one owner, a Builder Account or a platform workload, and the internal create's owner is the calling token's workload; an operator token carries none. Create the product from a Builder Account, or call the internal create with a workload token.
product_not_found No product exists for that account, or it is not visible to the caller. Create the product, or name the right account.
release_not_found The release does not exist in that product. Name a release from aircloud release list.
test_run_not_found The release has no test run in that environment. Name an environment from the release's test_runs (aircloud release show).
test_artifacts_not_found The test run pushed no artifacts (it produced no file past its report, or they exceeded the collection bound). Read the run's report and cause on the release; a run that writes artifacts carries them.
test_artifact_not_found The test run's artifacts hold no regular file at that path. Name a path the artifacts listing returns (aircloud release artifacts).
test_artifact_path_invalid The artifact path is not a clean relative path (absolute, empty segments or dot segments). Name the path exactly as the artifacts listing returns it.
test_artifact_too_large The artifact exceeds the size the platform answers for one file. Keep test artifacts small (screenshots and traces are far under the bound).
host_not_found No product serves that host. Check the host name.
migration_not_found The release declares no data migration by that name. Name a migration the release declares.
scope_not_found The secret scope is neither an environment of the product nor ci. Name an existing environment, or ci.
secret_not_declared The secret is not declared in the product's latest release. Declare it in config/secrets.toml and create a release first.
secret_too_large The secret value exceeds the size limit. Store a smaller value.
secret_value_invalid The secret value is empty or not UTF-8 text. Set a non-empty UTF-8 value.
secret_value_encoding_invalid The secret value does not decode under the key encoding its declaration names (config/secrets.toml key_encoding: base64, hex, or standard-webhooks — a whsec_-prefixed base64 secret). The value is not stored. Set the value exactly as the sender issued it, or declare the key_encoding that matches it (a Stripe whsec_ secret is text).
source_digest_mismatch The uploaded source does not match the digest the request declared. Upload again with aircloud release create.
rollback_contracting Rolling back would cross a contracting schema change, which the data cannot undo. Create a new release that restores the previous behaviour instead.
rollback_target_missing The environment has no previous release to roll back to. Activate a specific release instead.
locale_bundle_not_recorded The release records no compiled locale bundle. Create a new release; its resolve records the bundle.
tenant_not_in_good_standing The account is not in good standing, so it cannot release or activate. Bring the account back into good standing.
environment_reserved The ci and ci-* environments are owned by the platform. Choose another environment name.
environment_name_invalid The environment name is outside the environment grammar. Choose a name that follows the grammar.
name_conflict An active integration already holds that name. Choose another name, or retire the integration holding it.
not_pooled The tenant is not on the pooled data tier (unplaced, or already dedicated), so it cannot be promoted. Check the tenant's placement before promoting.
git_credential_invalid The git credential is not usable: its username or its token is empty. Register it again with a non-empty username and the token piped on stdin.
git_credential_not_found The product holds no git credential to delete. Nothing to delete; register one with aircloud git-credentials set when a private repository needs it.

Data-plane codes (what a product host answers an end user)

code HTTP answered by meaning remedy
route_not_found 404 web-origin, functions-host The host serves no product, the path is platform-reserved, no route matches, or a site asset is missing (the published 404).
product_unavailable 403 web-origin, functions-host The host's tenant is not in good standing (ADR-220).
release_pin_expired 409 web-origin, functions-host The request's release pin names a release the control plane no longer honours for this host; details.reload = true, and the pin cookie is cleared.
quota_exhausted 429 web-origin A hard_block plan's deploy.site.egress_bytes allowance is spent (runtime spec § Meter and lease).
deploy.site.quota_unavailable 503 web-origin The wallet is unreachable and this replica's one overdraft lease is spent (ADR-220 D4); Retry-After is set.
deploy.site.origin_unavailable 503 web-origin The control-plane resolver or the bundle store could not answer — fail-closed, no host is served on a resolution the replica could not make.
deploy.site.upstream_unavailable 502 web-origin The release-aware hop could not reach its container or route-trigger upstream.
deploy.site.not_acceptable 406 web-origin The request's Accept-Encoding refuses every published representation of the site file, identity included (RFC 9110 §12.5.3; #645 DX72).
deploy.site.i18n_report_invalid 400 web-origin A POST /_air/i18n-missing report is not the published {release, locale, key} body within its bounds (spec S4 § Run time).
session_required 401 web-origin A session route was requested with no end-user session: no session cookie, or a cookie naming no session record (#632, ADR-241 decision 3).
session_invalid 401 web-origin A session route was requested with a session that cannot be honoured: expired, revoked (a refresh the claims target refused, or a logout), bound to another product host (cross-product), or an unsafe method whose Origin is not the product host (#632, ADR-241 decisions 2 and 3).
session_role_required 403 web-origin A session route narrowed to any-of roles ([[authenticate.route]] roles) was requested by an admitted end-user session whose principal holds none of them (#250, ADR-254 decision 4). A site navigation receives the 403 page and every other request this envelope; never a sign-in redirect.
session_membership_required 403 web-origin A session route, or a selection at the membership switcher (/_air/memberships), needed a membership the authority projection grants the end user, and the session's selection names none (#384 run decision D76, ADR-293 decision 9): several memberships and none selected, a selection naming no membership of this end user (a forged or removed one), or a membership homed in an archived or unknown subtree. details.reason names which — membership_required | org_node_archived | org_node_unknown (contracts/auth/v1/authz-projection.json selection) — and details.memberships the switcher's path; a site navigation is sent to the switcher with its return_to instead. It is also the answer of a JSON POST /_air/workspaces whose new membership the projection did not carry within its propagation bound (contracts/auth/v1/account-lifecycle.json authority_projection.propagation_bound_seconds, run decision D85): the workspace exists and the selection is unchanged — select it at the switcher, never re-send the creation. Not retryable: the end user chooses. A principal the projection holds no key for at all is session_invalid (nothing to choose).
session_authz_unavailable 503 web-origin A session route needed the end user's authority — the selected membership, or a route's roles evaluated at its at node — and the web-origin's watch of the authority projection could not prove it is current within the projection bound (contracts/auth/v1/account-lifecycle.json), or the projection could not be read (#384, ADR-293 decision 8: fail-closed, never read as no restriction).
verification_session_outside_ci 404 web-origin A release verification session was asked for, or presented, outside the run it belongs to (#250, ADR-262 decisions 5 and 6): POST /_air/session/verification on a host that does not resolve to a ci- environment (refused before the control plane is asked), or a verification session presented on a host that no longer resolves to its ci- environment with its run in flight — that session record is deleted with the refusal.
verification_principal_refused 403 web-origin A release verification token was not redeemed (#250, ADR-262 decision 5): the host's environment is not ci-, its release has no verification run in flight, or the token is unknown, already spent or expired. One answer for every reason; the control plane's internal redemption answers it too.
verification_session_no_platform_reach 403 web-origin A release verification session reached a surface that forwards the end user's own token to a platform API, such as /_air/members (#250, ADR-262 decision 6): a verification session carries no end-user token and has no platform reach.
principal_assertion_invalid 401 functions-host A session route reached the route trigger without a valid platform-signed principal assertion: absent, unverifiable against the published web-origin principal key, expired, or for another product host (#632, ADR-241 decision 4 — the trigger verifies before admission and fails closed).
edge_rate_limited 429 air-edge An Air-Edge rate limit tripped before the tunnel (#632, ADR-240 decision 3, ADR-246): the per-IP anti-abuse floor every class keeps, the per-host bucket, a class's per-IP hourly bucket, the TENANT bucket of a verified canonical token on api/cap (the tenant's plan rate), or the PRODUCT bucket of a product host (its Builder's plan rate). details.scope names the bucket that refused: per_ip | per_host | per_ip_per_hour | per_tenant | per_product. Retry-After is set. Counted and audited as an edge event, never billed to the tenant.
edge_request_too_large 413 air-edge The request exceeded its route class's declared header-size or body-size limit, or did not deliver its body within the class's declared read-time limit, at the Air-Edge (#632, ADR-240 decision 3).
edge_request_refused 403 air-edge The Air-Edge WAF (SecLang + OWASP CRS v4 with platform overlays) refused the request before the tunnel (#632, ADR-240 decision 3). details carries no rule text. Resending the request unchanged is refused again: its content matched a platform WAF rule, or the WAF could not evaluate it. When it is a request your product's clients or the aircloud CLI legitimately send, report it with aircloud feedback, quoting the response's correlation_id: the edge audits every refusal by it, so the platform can name the rule the response never shows.
edge_path_noncanonical 403 air-edge The request path has more than one spelling, so the Air-Edge refused it before any route class was consulted (#250): a malformed or non-UTF-8 percent-encoding, a percent-encoded unreserved character (RFC 3986 § 2.3) or separator (/, \), an empty segment other than one trailing /, or a . / .. segment. The edge classifies every request on its ONE canonical path (edge/src/path.rs) and never rewrites one, so the origin and the edge cannot read a path differently. Sending the path in its canonical spelling succeeds. details carries no rule text.
edge_policy_unavailable 503 air-edge Signup or tenant-create was requested while the Air-Edge policy snapshot is stale (older than its declared maximum age) or absent: that class has no prior admission and is refused (jurisdiction 1; #632, ADR-240 decision 4 and Addendum 1). Every other class keeps the last snapshot or the declared floor; the published bound is that a principal may be served at the tier it held when the snapshot was cut for at most the snapshot's maximum age plus the alarm-to-repair time. Retry-After is set.
edge_host_mismatch 421 air-edge The request's Host is not the name its TLS connection was accepted for (SNI), or names no host the Air-Edge serves (RFC 9110 § 15.5.20 Misdirected Request). The edge classifies and routes by that one name, so a Host switched inside a connection is refused before the tunnel rather than classified as one host and routed as another (#632, ADR-240 decision 3). Retrying on a connection opened for the Host's own name succeeds.

CLI codes (what the aircloud CLI answers itself, before any request)

The CLI prints them as aircloud: <code>: <message> and exits 1; nothing reached the platform, so they never mean an outage.

code meaning remedy
auth.session_missing The command needs the Air-Cloud API and no session is stored for the identity it would act as: the product folder's account and region, else the account selected with aircloud accounts use. Nothing was sent: the CLI refuses before any network call. Log in to that account in that region: aircloud login --account <slug> --region <region> (the message names both), or select another logged-in account with aircloud accounts use. Automation sets AIRCLOUD_TOKEN and AIRCLOUD_API instead.
auth.session_expired The stored session of the identity the command would act as has expired, and no refresh token is held to renew it silently (no OS keychain, or the login predates it). Nothing was sent: the CLI refuses before any network call. Log in again: aircloud login --account <slug> --region <region> (the message names both).