Protecting sensitive data
Fluxzero offers built-in support for handling sensitive information with care using the @ProtectData and
@DropProtectedData annotations.
These tools help prevent sensitive fields (e.g., passwords, SSNs, tokens) from being unnecessarily stored, logged, or retained — supporting compliance with data protection standards like GDPR and ISO 27001.
@ProtectData: mark sensitive fields
Section titled “@ProtectData: mark sensitive fields”To prevent a field from being stored with the rest of a message payload, annotate it with @ProtectData:
public record RegisterCitizen(String name, @ProtectData String socialSecurityNumber) {}data class RegisterCitizen( val name: String, @ProtectData val socialSecurityNumber: String)When this message is dispatched, the socialSecurityNumber will be:
- Offloaded to a separate data vault when the message is published externally
- Redacted from the main payload (not visible in logs or message inspectors)
- Re-injected automatically when the message is handled
This happens transparently — you can access the field as usual in handler methods.
If a message is handled only by a local handler with logMessage = false, the original value remains in memory and is
passed directly to that handler without a KV write or read. External fallback and logMessage = true keep the normal
vault-backed behavior. @LocalOnly messages never externalize protected values.
@DropProtectedData: remove when done
Section titled “@DropProtectedData: remove when done”If the protected data should only be retained temporarily, annotate the handler method with @DropProtectedData:
@HandleCommand@DropProtectedDatavoid handle(RegisterCitizen command) { validate(command.getSocialSecurityNumber()); ...}@HandleCommand@DropProtectedDatafun handle(command: RegisterCitizen) { validate(command.socialSecurityNumber) ...}Once this handler completes:
- The injected
socialSecurityNumberis permanently deleted from storage, or discarded from memory for a local-only dispatch. - Future replays will deserialize the message with that field omitted.
Use cases
Section titled “Use cases”- Temporary use of sensitive tokens or credentials
- Compliance with data minimization and retention policies
- Preventing accidental exposure in logs or audits
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.
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