Is your feature request related to a problem? Please describe.
Feast returns null for features that are missing or explicitly null, so every consumer has to decide how to impute them independently. We've personally experienced this where a Go serving client might turn a missing transaction count into -1 while the training pipeline transforms to 0. As consumers grow ensuring consistency will become harder. That is training/serving skew created by the absence of a shared convention, and adding a new client means rediscovering each feature's missing-value semantics.
Noticed OnlineResponse.to_tensor(default_value=...) and RetrievalJob.to_tensor(default_value=...) do conversion-time replacement for tensors only. I haven't used these myself but think a similar approach could be implemented for to_dict() and to_df().
Feast owns the schema, registry, retrieval paths, statuses, and the ODFV execution boundary, so it's the only layer that can apply a default consistently before transformations in both the online and historical paths.
Describe the solution you'd like
Declare a typed default on the field:
Field(name="transaction_count", dtype=Int64, default_value=0)
Stored in FeatureSpecV2 as a feast.types.Value on field number 8 (currently free; Value.proto is already imported). Message presence distinguishes "no default" from a valid zero-like default such as 0, 0.0, false, or "".
Applied:
- after the historical point-in-time join
- during online retrieval in Python and Go serving
- before ODFV transformations execute
Could be applied here too but can already be done in the transformer code:
- to null ODFV outputs whose field declares a default
- optionally to missing/null RequestSource fields
Describe alternatives you've considered
- Client-side imputation: today's workaround duplicates semantics per client and permits skew.
- fillna() inside each ODFV: every transformation repeats it, and it doesn't help direct feature retrieval.
- A default_values={...} argument on retrieval calls: supports consumer-specific behaviour but establishes no reusable feature semantic, and training and serving can still diverge. Could be layered on later as an override above the schema default.
- Defaults in feature tags: avoids the proto change but is stringly typed and makes every runtime reinterpret metadata.
Additional context
Strictly opt-in. A field without default_value behaves exactly as it does today, and old registries without field 8 load unchanged.
Is your feature request related to a problem? Please describe.
Feast returns null for features that are missing or explicitly null, so every consumer has to decide how to impute them independently. We've personally experienced this where a Go serving client might turn a missing transaction count into -1 while the training pipeline transforms to 0. As consumers grow ensuring consistency will become harder. That is training/serving skew created by the absence of a shared convention, and adding a new client means rediscovering each feature's missing-value semantics.
Noticed
OnlineResponse.to_tensor(default_value=...)andRetrievalJob.to_tensor(default_value=...)do conversion-time replacement for tensors only. I haven't used these myself but think a similar approach could be implemented for to_dict() and to_df().Feast owns the schema, registry, retrieval paths, statuses, and the ODFV execution boundary, so it's the only layer that can apply a default consistently before transformations in both the online and historical paths.
Describe the solution you'd like
Declare a typed default on the field:
Stored in FeatureSpecV2 as a feast.types.Value on field number 8 (currently free; Value.proto is already imported). Message presence distinguishes "no default" from a valid zero-like default such as 0, 0.0, false, or "".
Applied:
Could be applied here too but can already be done in the transformer code:
Describe alternatives you've considered
Additional context
Strictly opt-in. A field without default_value behaves exactly as it does today, and old registries without field 8 load unchanged.