Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Error Codes

Every failure surfaced by Aperture is an APERTURE_* coded error. Each code carries a canonical message and, where operator action is meaningful, one or more fixup hints. This page is generated from the error Registry in errors/codes.go.

CodeMessageFixups
APERTURE_ACTION_UNDECLAREDaction is not declared on the object typeAdd the action verb to the object type's declared action set, or grant a verb the type already declares.
List the object type's actions to see the validated verb set.
APERTURE_ATTRIBUTE_PROVIDER_FETCHattribute provider returned an errorInspect the wrapped cause for the underlying provider failure.
Return APERTURE_NOT_FOUND from the provider for a key it does not know, so an unknown subject stays distinguishable from an unreachable directory.
APERTURE_ATTRIBUTE_PROVIDER_INVALIDattribute provider registration or attribute key is invalidRegister a non-nil provider, and at most one per LAYER: Register fills a slot's shared layer and RegisterLocal its local one, so a slot holds two and a third is refused. A duplicate within a layer is refused rather than replaced, so one directory cannot silently shadow another.
Declare a key set on a slot's SHARED layer only (Register with provider.WithDeclaredKeys): a declared key is reserved to the layer that declared it, so a local declared set would reserve keys against the deployment's own directory. A local layer takes cache options only.
Declare each attribute key at most once within a provider.
Fetch with a real key: a principal id for the user and machine slots, an account id for the account slot. An empty key names nobody.
Resolve the account wildcard "*" to a concrete account before fetching attributes; it is never a legal attribute key.
APERTURE_ATTRIBUTE_PROVIDER_UNREGISTEREDno attribute provider is registered for the slotRegister an AttributeProvider for the slot before fetching its attributes.
Check that the principal's kind maps to the slot you wired: a machine principal reads the machine slot, not the user slot.
Deployment genuinely has no subjects of this kind? Then nothing should be fetching that slot — fix the caller rather than registering an empty provider.
Seeing this from a decision? You should not: a Check/Enumerate/Explain against an unwired slot evaluates the floor bag and decides. This code reaches you only from a DIRECT attribute read (Fetch or Enumerate on the registry), so the caller to fix is that reader, not the decision path.
APERTURE_ATTRIBUTE_SLOT_UNKNOWNnot an attribute slotUse one of the three declared slots: user, machine, or account (provider.AttributeSlotUser / AttributeSlotMachine / AttributeSlotAccount).
Converting a principal kind that arrived as a bare string? Cross over with provider.ParseAttributeSlot so an unknown kind fails at the conversion instead of resolving to an empty attribute bag.
The slot set is closed on purpose — it names the parties a decision has. Model a further distinction as a FIELD in the bag, not as a fourth slot.
APERTURE_AUTHZ_DENIEDthe actor lacks the admin authority tier required for this mutationSchema mutations (permission types, roles, object-types, providers, templates, rules) require system-admin authority: an allow grant on the admin action whose object covers system:.
Grant and delegation mutations require account-admin authority in the TARGET account: an allow grant on the admin action whose object covers account:<acct>/admin:
.
Account-admin authority is confined to its own account; obtain authority in the account the mutation targets, or hold a broader (e.g. **) grant.
APERTURE_BOOTaperture failed to startCheck the APERTURE_* environment variables and any --config file.
Confirm the storage backend (memory or sqlite) is reachable.
APERTURE_CONFIG_INVALIDconfiguration is invalidValidate the YAML config and APERTURE_* env vars against the docs.
Enumerating an attribute slot that was declared without get_all: that slot is fetch-only by design, so add a get_all statement selecting a bare id, or read the slot through a fetch alone.
APERTURE_DELEGATION_DENIEDthe delegator may not bestow this grantBestow only grants that are a subset of your own effective allow grants in the account (same action and scope strategy, an equal-or-more-specific object pattern).
Confirm you hold a 'may delegate' right whose object pattern covers the grant's object.
Bestow grants only within an account you are a member of; cross-account bestowal is rejected.
APERTURE_DELEGATION_NOT_DELEGATABLEthe permission is not flagged delegatableSet Delegatable on the permission definition to allow it to be bestowed.
APERTURE_ENTITY_UNMANAGEDthis deployment does not manage the entity kind the write targetedSet the switch for the kind named in the message — APERTURE_MANAGE_ACCOUNTS, APERTURE_MANAGE_PRINCIPALS, or APERTURE_MANAGE_MEMBERSHIPS — to true (the default), then RESTART aperture: the switches are read once at startup and never re-read.
The three switches are independent; turning one on does not affect the others, so enable only the kind you meant to hand back to Aperture.
Leaving a kind unmanaged is usually deliberate — those records are mastered by an upstream system. Make the change there and let it flow in, rather than flipping the switch.
This is not a permission problem: no grant, role, or admin tier lifts it, and it refuses a system-admin exactly as it refuses anyone else.
APERTURE_IDENTITY_INVALIDobject identity is malformedUse type:id segments joined by '/', e.g. account:acme/project:atlas/document:42.
Ensure no segment is empty and every segment carries a ':' with a non-empty type and id.
Remove illegal characters; types and ids allow letters, digits, and -._~@+ only ('*' marks a wildcard in patterns).
APERTURE_IMPERSONATION_DENIEDthe operator may not impersonate this targetImpersonate only within an account both the operator and the target are members of; cross-account impersonation is refused.
Confirm the operator holds an impersonation right (augment or become) whose object pattern covers the target's identity.
Become mode requires the stronger become right; an augment right alone cannot become a target.
APERTURE_IMPERSONATION_EXPIREDthe impersonation session has expiredStart a fresh impersonation session; sessions are time-boxed and expire automatically.
APERTURE_INVALID_INPUTinput failed validationRe-check the request shape against the command or API contract.
APERTURE_INVALID_TOKENthe presented bearer credential failed verificationConfirm the token is a well-formed JWT signed by the configured issuer's keys.
Check the token issuer and audience match APERTURE_OIDC_ISSUER and APERTURE_OIDC_AUDIENCE, and that it has not expired.
For a parsec adapter, confirm the token was minted by the broker sharing the configured keyring/secret.
APERTURE_METADATA_INVALIDobject metadata violates the metadata value modelMake each field a scalar, a []any of scalars, or a map[string]any whose values are scalars, scalar arrays, or one further object level.
Replace an array of objects with a scalar array (e.g. a list of ids) — arrays of objects are rejected at any position.
Flatten a value that nests past the depth cap, or raise provider.ValueLimits.MaxDepth for the loader.
Shorten a value over the per-value size cap, or raise provider.ValueLimits.MaxBytes for the loader.
APERTURE_NOT_FOUNDthe referenced entity was not foundConfirm the identifier exists in the current account scope.
APERTURE_PROVIDER_FETCHobject provider returned an errorInspect the wrapped cause for the underlying provider failure.
Return APERTURE_NOT_FOUND from the provider for an object that does not exist.
APERTURE_PROVIDER_INVALIDobject provider registration is invalidRegister a non-nil provider under a non-empty object-type key.
Register each object type at most once; check for a duplicate registration.
APERTURE_PROVIDER_REFERENCE_INVALIDa declared object reference is not usableRegister a provider for the target object-type: a references: entry may only point at a type this registry serves.
Declare each field at most once per object-type; several fields may point at the same target, but one field has one target.
Declare the reference on the HOLDING side — the type whose provider actually returns the field — because that is the only side with a value to resolve.
Resolving a field means declaring it first: reg.DeclareReference("dataset", "current_brands", "brand"), or a references: entry in the provider's seed block.
APERTURE_PROVIDER_REFERENCE_MISMATCHa reference field's value does not identify an object of its declared target typeStore FULL canonical identities in a reference field ('brand:1', 'account:acme/brand:1'), not bare primary keys — compose them where the data is loaded, e.g. SELECT 'brand:' || b.id.
Make the field a string or a list of strings; a number, a map, or a list holding anything but strings cannot be an identity.
Check the declared target against the values the field actually carries: an identity whose terminal segment type is not the declared type is rejected rather than skipped.
APERTURE_PROVIDER_UNREGISTEREDno object provider is registered for the object typeRegister an ObjectProvider for the object type before fetching its metadata.
Confirm the object identity's terminal segment type matches a registered provider key.
Filtering an enumeration by metadata fields? Build the engine with engine.WithMetadata(registry) — the same provider registry the scope lister uses — or drop the field predicates.
Searching object metadata by name? Search ALWAYS needs engine.WithMetadata(registry); unlike a field predicate it is not optional, and an empty result would read as "no access" rather than as the misconfiguration it is.
APERTURE_RULE_EVALrule evaluation failedInspect the wrapped cause for the underlying evaluation failure.
Ensure the rule expression yields a boolean for the supplied context.
APERTURE_RULE_INVALIDrule AST is malformedGive each logical node the right child count: and/or take two or more, not takes exactly one.
Give every comparison a left and right operand, and every literal a scalar value.
Write variable references as dotted identifier paths, e.g. object.classification.
APERTURE_RULE_NOT_FOUNDthe referenced rule was not foundConfirm the rule reference exists in the configured rule source.
APERTURE_RULE_TYPE_ERRORrule failed expression type checkingCompare compatible types and make the rule evaluate to a boolean.
Call only functions registered with the rules engine.
APERTURE_RULE_UNDECLARED_ATTRIBUTErule reads an attribute key the wiring does not declareAdd the key to declared_keys: on the attribute_providers: entry for the slot the message names, then push the wiring again.
Or stop reading the key in the rule: a key no shared entry declares is served by at most one instance's local layer, so a rule over it decides differently per instance.
Read individual keys rather than the whole bag — a bare principal or account reference reads every key the bag happens to carry, which no declared set can cover.
A slot that declares no key set is not enforced at all; remove declared_keys: from the entry to opt that slot back out.
APERTURE_RULE_UNKNOWN_VARIABLErule references an unknown variableReference variables under a known context root: object, principal, account, or action.
Check for a typo in the variable's root segment.
APERTURE_SCOPE_INVALIDscope strategy reference is malformedUse 'strategy' or 'strategy;param=value' form, e.g. inclusive;ids=account:acme/document:42.
Give an inclusive/exclusive strategy an 'ids' list or a 'rule' reference; implicit takes no configuration.
APERTURE_SCOPE_LISTER_UNCONFIGUREDscope enumeration requires an object lister that is not configured— not applicable
APERTURE_SCOPE_RULE_UNCONFIGUREDscope rule path requires a rule evaluator that is not configured— not applicable
APERTURE_SCOPE_UNKNOWN_STRATEGYscope strategy is not registeredUse a built-in strategy (literal, implicit, inclusive, exclusive) or register the custom key with the scope registry.
APERTURE_SQL_PROVIDER_AMBIGUOUSSQL provider's fetch statement returned more than one row for one keyFilter the fetch statement on a unique or primary key so one identity — or one subject id — selects at most one row.
A join that fans out is the usual cause; aggregate or de-duplicate the fanned-out side instead of adding LIMIT 1, which would make the metadata depend on an unspecified row order.
APERTURE_SQL_PROVIDER_CONNECTIONa declared database connection could not be resolved into a live poolSet the environment variable named by the connection's dsn_env: to a non-empty DSN before starting the process.
Check that every kind: sql provider entry's connection: matches a name declared in the top-level connections: block.
Give pool settings valid values: conn_max_lifetime and query_timeout are Go durations ("30m", "5s"), and query_timeout must be positive — there is no 'no timeout' setting.
Verify the DSN's host, port, database, and credentials by connecting with psql; the driver's message is redacted here because a DSN parse failure commonly echoes the password.
APERTURE_SQL_PROVIDER_DSN_LITERALa declarative database connection carries a literal dsn instead of dsn_envReplace the connection's dsn: key with dsn_env: naming the environment variable that holds the DSN.
Export the DSN in the process environment (or a .env file the deployment loads) rather than writing it into the seed file.
Rotate the credential if a literal DSN was ever committed — the seed file is a version-controlled artifact.
APERTURE_SQL_PROVIDER_QUERYSQL provider could not run its statementInspect the wrapped driver error for the underlying database failure.
Check the statement's placeholder count: a fetch statement binds exactly one parameter — the identity's terminal segment value for an object provider, the bare subject id for an attribute provider.
Use the placeholder syntax your engine speaks — Aperture passes placeholders through untouched and never rewrites $1 to ?.
Confirm the database is reachable and the connection's role can read the table; raise Config.Timeout if the statement is legitimately slow.
APERTURE_SQL_PROVIDER_ROW_IDENTITYSQL provider could not turn a row's id column into a usable keyObject provider: compose the full identity in the get-all statement's id column — SELECT 'brand:' || b.id AS id — because a bare primary key is not an identity and Aperture supplies no template.
Attribute provider: select the BARE subject id — SELECT u.id AS id — and never 'user:' || u.id, which is a legal opaque key that no principal id will ever match, so the slot enumerates and then answers nothing.
Name the key column id, or set the provider's id column to the alias the statement actually uses.
Make the id column textual and never NULL: cast a numeric or uuid key with ::text before concatenating it.
Check that the identity's terminal segment type is the object-type this provider is registered under; a 'brand:1' row served by the 'dataset' provider is rejected rather than cached.
APERTURE_SQL_PROVIDER_SCANSQL provider could not read a row into metadataGive every selected expression a name, and alias duplicates: each result column becomes a metadata field keyed by its column name.
Cast or serialise a column whose Go type the provider does not map (the driver value's type is named in the error, alongside the types that are mapped).
A []byte column is decoded as JSON, never as a string: wrap an array in to_jsonb(...), and cast a numeric, uuid, or bytea to ::text, ::float8, or encode(...) in the statement.
A list-valued field only arrives as a list when the statement casts it — SELECT to_jsonb(tags) AS tags, not SELECT tags, which yields the raw array literal as a string that silently matches nothing.
APERTURE_STORAGEthe storage backend returned an errorInspect the wrapped cause for the underlying storage failure.
APERTURE_STORAGE_CONSTRAINTthe database refused the write because it would break referential integrityDelete the rows that reference the record first: a principal's memberships and group memberships, a permission's role assignments and grants, a role's principal assignments, an object type's permissions, an account's memberships and grants, and the grants that name a principal, role, or group as their subject.
Creating a record? Create what it references first — a permission needs its object type, a membership and a group member need their principal, a grant and a role assignment need their permission, and a membership and a grant need their account.
Refused on a grant's subject? subject_kind chooses the table subject_id must exist in — principal, role, or group. A grant naming a role id under kind "group" is refused even though that id exists elsewhere.
Refused on an account id? It must name a real account, or be exactly "" (the all-accounts wildcard). "" is a sentinel, not an account: it needs no account record and cannot be given one.
Ids are immutable in Aperture: to change one, create the new record, move the children, then delete the old one — an UPDATE that moved a key is refused rather than silently re-parenting.
Seeing this from Setup rather than a write? The connection is not enforcing foreign keys. Open the store with sqlite.Open, which forces _pragma=foreign_keys(1) into the DSN whatever the caller passed.
APERTURE_STORAGE_SCHEMA_INCOMPATIBLEthe existing database was written by an incompatible build and cannot be upgradedRecreate the database: move or delete the old file, start Aperture so Setup builds the schema fresh, then re-seed it.
Point the store at a new, empty database if you need to keep the old file for reference.
Do not expect an in-place upgrade: Aperture ships no migration tool and no schema versioning, so a schema break is a hard break by design.
APERTURE_TEMPLATE_INVALIDthe provisioning template is malformedGive the template a non-empty name, a version of at least 1, and at least one grant.
Declare every parameter a grant references; write references as ${name} with a declared parameter.
Give each template grant a valid subject, a permission id, an allow/deny effect, and a non-empty object pattern.
APERTURE_TEMPLATE_PARAMthe template apply supplied invalid parametersSupply a value for every parameter the template declares, and no parameters it does not.
A segment-typed parameter value must be a legal identity component: letters, digits, and -._~@+ only.
APERTURE_UNAUTHENTICATEDthe request could not be resolved to a known principalPresent a credential: send an Authorization: Bearer <token> header.
With the dev/static authenticator the bearer IS the principal id; send a non-empty value.
Confirm the verified token carries the configured principal claim (APERTURE_AUTH_PRINCIPAL_CLAIM, default 'sub').
APERTURE_UNIMPLEMENTEDthis surface is not yet implemented— not applicable
APERTURE_WIRING_CONNECTION_UNDECLAREDa pushed entry names a connection the wiring's connections: manifest does not declareAdd the connection named in the message to the document's connections: block, with dsn_env: naming the environment variable that holds its DSN.
Or fix the entry's connection: to match one of the declared names the message lists — one connections: entry is one pool, so a typo opens no pool rather than a second one.
Only the NAME is shared: every instance resolves that connection's DSN and pool settings from its own environment, so the manifest is a list of names and nothing else.
APERTURE_WIRING_CONNECTION_UNROUTEDthe shared wiring declares a connection name this instance has no route forExport the environment variable the message names — APERTURE_CONNECTION_<NAME>_DSN — with this instance's DSN for that connection. It is the conventional route and needs no seed file.
Or declare a connections: entry under the same name in this instance's --seed file, with dsn_env: naming a variable of your choosing; a local entry is that name's route, not a competing declaration, and it also carries the pool sizes and query_timeout.
Or, in a Go host, supply seed.WithConnectionOpener and build the pool for that name yourself — the one seam a host needs, and the only one that never reads a DSN from the environment.
Check which names this deployment expects with aperture wiring show --store &lt;dsn&gt;: the shared tables carry the connection NAME and nothing else, so every instance must supply its own route for each one.
Do not work around it by removing the entry that uses the connection: an object provider that cannot reach its database yields no metadata, and an attribute provider that cannot yields a nil bag — which widens an exclusive grant rather than denying.
APERTURE_WIRING_EMPTY_PUSHthe document being pushed declares no shared wiring at all, and a push is a REPLACECheck the --seed path first: the likeliest cause is the wrong file, and the second likeliest is a mistyped section key (provider: for providers:, field_type: for field_types:), which the seed reader does not refuse — it simply reads no section.
Confirm what the document declares with aperture wiring push --seed &lt;file&gt; --store &lt;dsn&gt;'s summary on a store you do not mind replacing, or read the file's four shared sections directly: connections:, providers:, field_types:, attribute_providers:.
If retiring the deployment's wiring really is the intent, pass --allow-empty. Every instance then builds its wiring from its own --seed file again, and an instance with no --seed file builds NONE — an empty object registry and an empty attribute registry, which still starts.
Retiring an attribute slot is the dangerous half: an unregistered slot answers with an empty bag, and a rule that EXCLUDED on an attribute it can no longer see stops excluding, so the grant widens with nothing in a verdict, a trace or a note to say so. Prefer pushing a document that keeps the slots and changes what you meant to change.
aperture wiring show --store &lt;dsn&gt; prints what is deployed right now, and aperture wiring pull --out &lt;file&gt; writes it out as a document you can edit and push back.
APERTURE_WIRING_KIND_UNSHAREABLEa pushed entry selects a kind that cannot be shared wiringReplace the kind: csv entry named in the message with kind: sql reading through a connections: entry, so every instance reaches the same data without a shared filesystem.
Or leave that entry out of the pushed wiring and keep it in the LOCAL seed document, where the path belongs to the instance that reads it.
A csv entry's only data source is a filesystem path; the shared-wiring schema has no path column, because a relative path resolves against the seed file's own directory and an absolute one is a guess about the other host's disk.
On a BOOT this refusal means the row is already deployed — written by hand, or by a build that predates the check. Re-push a wiring document without it (aperture wiring push), or read the same data through kind: sql; there is no path column to add a path to.
APERTURE_WIRING_LOCAL_COLLISIONthe local seed file declares an object type or attribute slot the shared wiring already declaresDelete the local declaration named in the message: with wiring rows present the database is authoritative, and the local file may only ADD an object type or slot the database never declared.
Or remove the shared declaration instead — push a wiring document that omits it (aperture wiring push --store &lt;dsn&gt; --seed &lt;file&gt;) — if the local one is the wiring you actually want the fleet to use.
Check which side declares what with aperture wiring show --store &lt;dsn&gt;, then read the same section of this instance's --seed file.
A host registering its own providers in Go gets the same refusal from the registry as APERTURE_PROVIDER_INVALID: the rule is about the registry, not about which syntax declared the entry.
APERTURE_WIRING_NOTHING_DEPLOYEDthe store has no shared wiring deployed, so there is nothing to pullCheck the --store DSN first: a typo names a database that does not exist yet, Setup creates it empty, and an empty read is exactly what that looks like.
If the DSN is right, nothing has been pushed to this deployment yet — run aperture wiring push --seed &lt;file&gt; --store &lt;dsn&gt;, and every instance sharing the database will read it.
aperture wiring show --store &lt;dsn&gt; describes an empty store without refusing, which is the command to use when you only want to know whether anything is deployed.
A pull is refused rather than writing an empty document because that document, pushed back, would replace the deployment's wiring with nothing.
APERTURE_WIRING_NO_MODEL_STATEthe target store holds no model state, so there is nothing for the pushed wiring to be wiring forApply model state to this store first — aperture import --store &lt;dsn&gt;, aperture serve --store &lt;dsn&gt; --seed &lt;file&gt;, or the mutation commands — and then push the wiring.
Check the --store DSN: a typo names a database that does not exist yet, Setup creates it empty, and the wiring would land somewhere no instance reads.
Two instances sharing wiring must share the MODEL too; wiring says where object metadata and attribute bags are read from, not who exists.
APERTURE_WIRING_OBJECT_TYPE_UNKNOWNa pushed provider entry serves an object type the model does not declareDeclare the object type named in the message in the store's object_types: (apply the model state, then push the wiring again).
Check the spelling against aperture list object-type --store &lt;dsn&gt;: the wiring's object_type: must equal the object type's name exactly.
Field-type declarations are exempt — they may name a type whose objects a local seed lists inline — so only providers: entries need a row.
APERTURE_WIRING_OUTPUT_EXISTSthe --out path already exists and would be overwrittenWrite to a new path and compare the two files yourself — the existing file is usually the version-controlled document the pull is meant to be diffed against.
Pass --force to replace the file deliberately.
Nothing was read from the store and nothing was written: the path is checked before the wiring is fetched, so a refusal here leaves both the file and the deployment untouched.
APERTURE_WIRING_REFRESH_FAILEDa background re-read of the shared wiring failed, so this instance is still deciding from the wiring it hasNothing is broken about this instance's decisions: it kept the last wiring it successfully read and is still answering. What it has lost is the ability to notice a aperture wiring push, so treat it as a deployment that has drifted, not as an outage.
Read how long it has been stale with the system-admin-gated WiringPosture read (the WiringPosture RPC), which reports the duration, the failure count and the code — an alarm minutes old on a restarting database is ordinary, and the same alarm hours old is a fleet enforcing policy somebody already retired.
The alarm normally carries the underlying failure's OWN code and fixups; follow those first. Seeing this code itself means nothing underneath it was coded, which is worth reporting.
Check the store is reachable from this host and that its wiring tables match this build (aperture wiring show --store &lt;dsn&gt;): an unreachable store and a schema from an older build are the two commonest causes.
If the push added a connection name, every instance needs its own route for it — export APERTURE_CONNECTION_<NAME>_DSN, or declare the name in this instance's --seed file. See APERTURE_WIRING_CONNECTION_UNROUTED.
Restarting the instance is the way to force the matter, and it is safe: a boot re-reads the shared wiring from scratch and REFUSES to start on wiring it cannot build, rather than degrading.
APERTURE_WIRING_RESTART_REQUIREDthe deployed wiring changes this instance's connection name set, which is fixed for the life of a processRestart this instance to adopt the push. The connection NAME SET is resolved once, at boot, because a route — which server, which credential, how big a pool — is a per-instance fact the shared tables carry no column for.
For each name the message says the push ADDS, supply this instance's route first: export APERTURE_CONNECTION_<NAME>_DSN, or declare a connections: entry under the same name in this instance's --seed file, or supply seed.WithConnectionOpener in a Go host. Then restart.
For each name the message says the push DROPS, nothing needs supplying: the pool stays open and this instance goes on deciding through the wiring it has until it is restarted.
Nothing else in the push was applied either — a push is adopted whole or not at all — so the providers, field types and attribute providers pushed alongside the connection change are still outstanding and land on the restart.
Check what the deployment expects with aperture wiring show --store &lt;dsn&gt;; the shared tables carry the connection NAME and nothing else, so every instance supplies its own route for each one.