Protecting sensitive data
Some message fields should be available during processing without remaining in the message history. Use
@ProtectData to store such a field separately, and @DropProtectedData to remove that protected value when it
is no longer needed. The rest of the message can remain available for tracing and replay.
For a minimal command and its final-use handler, follow Protect and erase PII.
@ProtectData: mark sensitive fields
Section titled “@ProtectData: mark sensitive fields”ProtectData marks a payload field whose value is stored separately when the message is published. The stored payload contains a reference; handlers receive the restored value.
A local-only invocation without message logging can pass the value in memory without writing the vault.
@LocalOnly does not suppress Model or document writes performed by your handler.
@DropProtectedData: remove when done
Section titled “@DropProtectedData: remove when done”DropProtectedData marks a handler as the final use of its payload’s protected values. The values are restored for that invocation and their retained copies are deleted. Subsequent processing cannot recover them. Do not rely on the annotation to retain data for retries after handler failure.
Protection does not redact values you copy into logs, Model state, documents or snapshots. See Model state and protection boundaries.
Replays and protected data
Section titled “Replays and protected data”During replays, if a message with protected fields is re-invoked after data has been dropped, those fields will be
missing or set to null.
Independent Model events
Section titled “Independent Model events”Model updates also protect their stored and published events. Reconstructing a Model restores retained values;
erased fields become null, so replay applies must tolerate missing private data. Custom serializers must describe
their serialized property paths correctly; unsupported mappings fail before committing private values.
See ProtectData and Serializer for these contracts.
Missing protected data policies
Section titled “Missing protected data policies”Handlers can choose how to respond when protected values referenced by a message are no longer available:
@HandleEvent(onMissingProtectedData = MissingProtectedDataPolicy.SKIP)void handle(CitizenRegistered event) { ...}@HandleEvent(onMissingProtectedData = MissingProtectedDataPolicy.SKIP)fun handle(event: CitizenRegistered) { ...}The available policies are:
HANDLE: invoke silently with unavailable fields set tonull(SDK default)WARN: log a warning and invoke with unavailable fields set tonullSKIP: skip only this handler invocation and advance tracking normallyFAIL: fail through the consumer’s normal error handlingDEFAULT: inherit from the consumer or application configuration
The effective policy is resolved from the handler, consumer, builder, application property, and finally the SDK
default. Configure the application fallback with
DefaultFluxzero.builder().onMissingProtectedData(...) or:
fluxzero.dataProtection.onMissingProtectedData=WARNFor environment variables, both FLUXZERO_DATA_PROTECTION_ON_MISSING_PROTECTED_DATA and the compact Spring-style
FLUXZERO_DATAPROTECTION_ONMISSINGPROTECTEDDATA are supported.
When tracking metrics are enabled, SKIP emits an IgnoreMessageEvent with reason missingProtectedData.
- Only fields can be annotated with
@ProtectData(not method parameters). - Dropping data is irreversible. Make sure all processing is complete before it is removed.
- Support for nested structures is currently limited — annotate each sensitive field explicitly.
© 2026 Fluxzero