Skip to content

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 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 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.

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.


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.

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) {
...
}

The available policies are:

  • HANDLE: invoke silently with unavailable fields set to null (SDK default)
  • WARN: log a warning and invoke with unavailable fields set to null
  • SKIP: skip only this handler invocation and advance tracking normally
  • FAIL: fail through the consumer’s normal error handling
  • DEFAULT: 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=WARN

For 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