Skip to main content

Validate

validate: is a step-level primitive that attaches validation rules directly to a source, transformer, or destination. It is a declarative description, like cache or consent: consumers (CLI, MCP, custom runners) decide how to enforce.

"destinations": {
"ga4": {
"package": "@walkeros/web-destination-gtag",
"validate": {
"events": {
"order": {
"complete": { "properties": { "data": { "required": ["total"] } } }
}
}
}
}
}

The shape

validate is an object with three optional fields. At least one must be set for the primitive to do anything.

FieldTypeDescription
format?booleanCheck the full WalkerOS.Event structural shape (name, source, timestamp, etc.)
events?Record<entity, Record<action, JsonSchema>>Per-event JSON Schemas keyed by entity then action, with * wildcard fallback
schema?JsonSchemaA single JSON Schema applied to every event that reaches the step

events or schema

Per-event rules go in events. Apply-to-every-event rules go in schema.

Step-level usage

validate: lives on the step it protects. Same shape on every step type.

On a destination

Declare that orders without a total should not reach GA4. Other destinations on the same flow are unaffected by this declaration.

Loading...

On a source

Declare ingest payloads that miss a required field as invalid before they hit the collector.

Loading...

On a transformer

Declare a precondition for a transformer, for example that a downstream enrichment transformer never sees an event without a user id.

Loading...

Failure semantic

validate: is declarative, runtime behavior depends on the consumer. The typical interpretation is local to the step: a failed validation skips the step it is attached to and other destinations, transformers, and sources on the same flow continue to receive the event. Treat this as the recommended convention, not a guaranteed runtime contract.

                         ┌──────────────────────────┐
│ ga4 (validate fails) │
event "order complete" ──┤ skipped │
│ │
│ meta (no validate here) │
│ receives event │
└──────────────────────────┘

This local-to-the-step semantic is the key difference from a flow-level validator that drops events globally.

Lifecycle position

The recommended logical position is after the step's before chain and before the step's main action. On a source that places validation in front of the collector, on a transformer or destination it sits in front of the main push. The validator sees the event in the same shape the step itself would see.

Wiring from a contract

validate: accepts $contract.<name>.<path> references just like any other config value. Define rules once in a contract, reference them from each step:

Loading...

See Contract for the full contract shape, inheritance with extend, and wildcard merging.

Format layer

Setting format: true declares that the full WalkerOS.Event structural check should run on the input. That covers required top-level fields (name, source, timestamp, id, ...), the entity-action event name pattern, source.type being one of the known kinds, and the basic shape of nested objects (data, context, globals, user, consent). Use it as a cheap sanity gate when the step receives data from arbitrary callers, skip it when the input is already a WalkerOS.Event produced by the collector.

Next steps

  • Contract: named, inheritable schemas referenced via $contract
  • Mapping: transform events between steps
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)