# 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 :[:][:required] | | `generate.bad_option` | generate | an option value or combination is not allowed | | `generate.bad_name` | generate | a generator's 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// 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// 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: ` 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//nodes/