- SDKs & APIs
- Reserved Names
Reserved Names
Ironflow owns a few name roots. This page lists each root and the rule for it. A rejected write fails with an error. Ironflow never ignores it silently.
Names in an Ironflow-owned namespace have meanings that Ironflow defines. A minor release may add names to these namespaces and may restrict who can write them. Using an owned namespace for your own data is unsupported.
Loosening a rule is never a breaking change. Tightening a rule inside an owned root is allowed in a minor release. See ADR 0128.
The rule applies when you create, register or emit a name. Two surfaces also check reads: an entity stream ID (stream reads, snapshots and info) and a KV bucket name (get, list and delete). Other reads and subscriptions are not restricted.
| Surface | Root | Rule |
|---|---|---|
event-name | ironflow. | Rejected, except the writable defined name ironflow.invoke.<fn> on Emit, Trigger, TriggerSync and TriggerBatch, and only with functions:invoke. NATS ingest rejects it. |
event-name | $ | Rejected. Entity tombstones use this root. |
webhook-event-prefix | ironflow. | Rejected when the prefix plus a dot starts with the root, so ironflow alone is rejected too. |
webhook-event-prefix | $ | Rejected when the prefix starts with the root. |
entity-id | ironflow: | Rejected. The match ignores case. |
kv-bucket | SYS_ | Create returns 400. Other routes return 404. Delete returns 403. |
kv-bucket | ENV_ | Create returns 400. Other routes return 404. |
kv-bucket | config_env_ | Create returns 400. Other routes return 404. |
kv-bucket | MOD_ | Create returns 400. Other routes return 404. |
projection-name | ironflow_ | Rejected before the definition is stored. |
pubsub-topic | events: | Publish rejected. |
pubsub-topic | system. | Publish rejected. |
pubsub-topic | entity: | Publish rejected. |
pubsub-topic | public. | Publish rejected. |
pubsub-topic | topic: | Publish rejected. |
rego-package | data.ironflow | Rejected, except ironflow.authz and ironflow.authz_test. |
environment-name | current | Rejected on create and rename. The rule matches the whole name, not a prefix. |
Event roots, MOD_ and ironflow_ match exact case, because event names, NATS subjects and KV bucket names are case-sensitive. Entity IDs match without regard to case.
Event schema registration rejects every event name that a user cannot emit. A schema never applies to a platform event, so Ironflow rejects it instead of accepting it silently. The writable defined name ironflow.invoke.<fn> still takes a schema, because Emit enforces schemas on it.
Errors
Section titled “Errors”- Event names, webhook prefixes, event schemas, projection names, pub/sub topics: ConnectRPC
invalid_argument. - Entity IDs: ConnectRPC
permission_denied. - KV buckets: HTTP 400, 404 or 403, as the table shows.
- Rego packages: error code
policy_set_reserved_namespace. - Environment names: HTTP 400, or
invalid_argumenton ConnectRPC.
Payload markers
Section titled “Payload markers”Two JSON keys inside a payload are Ironflow-owned too (ADR 0133).
| Surface | Root | Rule |
|---|---|---|
payload-marker | $enc | An object whose only member is $enc, at any depth. Reserved by contract. No door rejects it in 1.0. |
payload-marker | $redacted | A top-level member. Rejected on every payload write that a user or worker makes. |
Ironflow writes $redacted when it redacts a payload (RedactEvent, RedactStep, RedactRun). The check reads only the top level, so a nested $redacted passes. These writes reject a payload with a top-level $redacted member, whatever its value:
- The event doors:
Trigger,Emit,TriggerSync,TriggerBatch,PubSubService.Emit,EntityStreamService.AppendEvent, webhook ingest and NATS ingest. InvokeFunction,InvokeFunctionSyncand the input of a child invoke step.PatchStepandInjectStepOutput.- A step output, run result or
waitForEventpayload that a worker sends, in push and pull mode. - A step error that a REST pull worker sends. It fails the run with
RESERVED_PAYLOAD_MARKER; a checkpoint or yield that carries one also answers HTTP 400.
The RPCs answer ConnectRPC invalid_argument. Webhook ingest answers HTTP 400. NATS ingest terminates the message. A worker result fails the run with the code RESERVED_PAYLOAD_MARKER, and the run is not retried. A child invoke input fails the invoke step. For invoke, the parent run fails too. For invokeAsync, the parent run continues. A waitForEvent payload is rejected as an invalid yield, and the run fails with YIELD_REJECTED in push and pull mode.
Redacted data cannot come back as output. A function whose input was redacted and that then returns a top-level $redacted member, for example by spreading event.data into its result after a resume, fails with RESERVED_PAYLOAD_MARKER.
A later release gives $enc a meaning. Data that uses it is unsupported.
Event names inside ironflow.
Section titled “Event names inside ironflow.”Every event name that starts with ironflow. is one of three kinds.
Writable defined name. Your code can emit this name through Emit, Trigger, TriggerSync and TriggerBatch. A non-empty suffix must follow the prefix. The suffix can contain dots. The caller needs functions:invoke on function <fn>, as for InvokeFunction; without it the emit returns 403. The event starts only function <fn>. A trigger on any other function does not match it, a wildcard such as > included. A NATS publisher to events.ingest.> cannot emit this name, and a webhook cannot either.
ironflow.invoke.<fn>: the event thatironflow invokeemits for function<fn>.
Platform-only names. Only Ironflow writes these. A client emit is rejected.
ironflow.file.*andironflow.bucket.*: file and bucket events.ironflow.cron.<fn>: a cron schedule fired for function<fn>.ironflow.function.invoked: a function was invoked.
Every other name. No rule defines it, so a client emit is rejected. A later release can define it.
Webhook ingest and entity stream appends get no exceptions. They reject every owned name, the writable defined name included. An entity append wakes waiting runs too, so entities:append alone cannot start an invoke.
What stays open
Section titled “What stays open”- A function trigger can match an owned name, for example
ironflow.file.*orironflow.invoke.<fn>. - You can subscribe to and read owned events.
- Reading an entity stream with an
ironflow:ID is still rejected.
Names that already exist
Section titled “Names that already exist”Ironflow runs these checks only on user calls: create, register, emit, and the entity stream and KV bucket reads. Server start and rebuild never run them. A stored name under a new root cannot block startup. Ironflow does not migrate old names.
- A stored projection named
ironflow_*stays. Its next re-register fails. - A KV bucket named
MOD_*stays. Every route except create returns 404, like the other reserved prefixes. - A webhook source whose
event_prefixis under an owned root stays. A delivery fails with 400 when its event name starts under an owned root. For the prefixironflowalone, that means a delivery that carries an event type, because a delivery with no type uses the bare nameironflow. - An environment named
currentstays. APUTthat keeps the namecurrentfails until you rename the environment. - A stored payload with a top-level
$redactedmember stays. Only new writes are rejected. - Stored events keep their old names. The cron and invoke events moved from
ironflow/cron.<fn>andironflow/function.invokedto the dotted names above. The old names stay in history.