Event Sanitizers
Event sanitizers let you remove or replace observability data on mark and scope events before the runtime sends the events to subscribers or exporters. Use them for event data that the tool and LLM request or response sanitizer APIs do not cover. They do not change the real request, response, or callback result.
Sanitizer Surfaces
Choose a registry based on the event that you want to sanitize.
Scope sanitizers apply to every scope category, including tool and llm.
For tool and LLM events, the specialized request or response sanitizers run
first. Your scope sanitizer then receives the already-sanitized event fields,
which lets a general event policy inspect them without changing the real
request or response.
Callback Contract
When the runtime calls a sanitizer, it provides the following values:
- The complete event as immutable context.
- An
EventSanitizeFieldsvalue withdata,category_profile, andmetadata.
Return the replacement values for those three observability fields. The return
value replaces the fields; it does not patch them. Start with the supplied
fields, modify the fields that need to change, and return all three. In
bindings that accept a partial object, omitting a field can clear it. To remove
a field explicitly, use None in Rust or Python, null in Node.js, or a
zero-value json.RawMessage in Go.
Sanitizers can change only data, category_profile, and metadata. They
cannot change event identity, parentage, timestamps, kind, scope category,
semantic category, attributes, semantic input and output meaning, or schemas.
Registries run in priority order. Lower priorities run first, and each
callback receives the fields returned by the callback before it. Invalid
binding callback results fail open and preserve the current fields. In Node.js,
a synchronous sanitizer callback that throws also fails open; Relay records the
error for getLastCallbackError().
Registration Lifetimes
Where you register a sanitizer determines how long it stays active.
- Global registrations stay active until you explicitly deregister them.
- Scope-local registrations are inherited by descendant scopes and are removed when the owning scope closes.
- Plugin-context registrations belong to the component instance. The runtime rolls them back if activation fails or you clear the plugin configuration.
Register a Global Mark Sanitizer
The following examples replace mark data and remove mark metadata while preserving the category profile.
Python
Node.js
Rust
API Names
Use the matching start and end APIs when a policy applies to duration-bearing scope events. The following APIs register sanitizers at each level.
Each registration API has a matching deregistration API. Python scope-local helpers accept a scope handle. Node.js and Rust scope-local helpers accept the owning scope UUID.
Plugin contexts expose the same three surfaces as
register_mark_sanitize_guardrail,
register_scope_sanitize_start_guardrail, and
register_scope_sanitize_end_guardrail, using each binding’s naming
convention.
Dynamic Plugins
Rust native plugins receive the three registration methods on their typed
plugin context. Python grpc-v1 workers receive the same methods on
PluginContext, and their callbacks can be synchronous or asynchronous. The
worker protocol remains grpc-v1 and defines the following stable registration
surface values:
MARK_SANITIZE_GUARDRAIL = 30SCOPE_SANITIZE_START_GUARDRAIL = 31SCOPE_SANITIZE_END_GUARDRAIL = 32
Declare only the surfaces that your dynamic plugin installs. Register them through the plugin context so the runtime rolls back every registration if activation fails.
Experimental C and Go Bindings
The source-first C API uses NemoRelayEventSanitizeCb. It provides global,
scope-local, and plugin-context registration functions for all three surfaces.
Global names start with nemo_relay_register_, and scope-local names start
with nemo_relay_scope_register_.
The Go binding provides EventSanitizeFields, EventSanitizeFunc, global
Register*SanitizeGuardrail helpers, scope-local
ScopeRegister*SanitizeGuardrail helpers, and the same methods on
PluginContext. The guardrails package provides shorter aliases. Because a
returned EventSanitizeFields replaces all three fields, copy the supplied
value and modify only the fields that should change.
Related Topics
For related concepts and configuration, refer to the following topics: