GeezerVison is showing github.com — Calling get_historical_features for a feature service with an on_demand_feature_view expects the code locally · Issue #5620 · feast-dev/feast
Calling get_historical_features for a feature service with an on_demand_feature_view expects the code locally #5620DescriptionExpected Behavior
Feature retrieval should not depend on local code. This also causes issues deleting/updating the feature store via the CLI.
Current Behavior
If I register a feature service that uses an on_demand_feature_view and try to get historical features from it I get the following error:
Traceback (most recent call last):
File "/Users/user/Git/repo/test.py", line 14, in <module>
features = feature_store.get_historical_features(
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/feature_store.py", line 1171, in get_historical_features
) = utils._get_feature_views_to_use(self._registry, self.project, features)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/utils.py", line 1075, in _get_feature_views_to_use
fv = registry.get_any_feature_view(name, project, allow_cache)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/infra/registry/registry.py", line 641, in get_any_feature_view
return proto_registry_utils.get_any_feature_view(registry_proto, name, project)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/infra/registry/proto_registry_utils.py", line 92, in wrapper
value = func(registry_proto, name, project)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/infra/registry/proto_registry_utils.py", line 145, in get_any_feature_view
return OnDemandFeatureView.from_proto(on_demand_feature_view)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/on_demand_feature_view.py", line 393, in from_proto
transformation = PandasTransformation.from_proto(
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/feast/transformation/pandas_transformation.py", line 150, in from_proto
udf=dill.loads(user_defined_function_proto.body),
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/dill/_dill.py", line 311, in loads
return load(file, ignore, **kwds)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/dill/_dill.py", line 297, in load
return Unpickler(file, ignore=ignore, **kwds).load()
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/dill/_dill.py", line 452, in load
obj = StockUnpickler.load(self)
File "/Users/user/.pyenv/versions/repo/lib/python3.10/site-packages/dill/_dill.py", line 442, in find_class
return StockUnpickler.find_class(self, module, name)
ModuleNotFoundError: No module named 'feature_services'
I don't get this error if I'm running it from a location that it can find this module, but of course we want to deploy this feature service to the feature store and call it from elsewhere.
Steps to reproduce
I am using a Redshift Offline Source.
feature service code:
merchandisability_feature_store = FeatureService(
name="merchandisability",
features=[
artwork_inquiries_feature_view,
artwork_metadata_feature_view,
artist_metadata_feature_view,
partner_metadata_feature_view,
purchase_metadata_feature_view,
artwork_age, <-- on demand feature view
],
)
and I try to get features like so:
df = pd.DataFrame.from_dict(
{"user_id": ["user1"], "event_timestamp": datetime.now()}
)
feature_service = feature_store.get_feature_service("merchandisability")
features = feature_store.get_historical_features(
features=feature_service,
entity_df=df,
)
Specifications
- Version: 0.53.0
- Platform: MacOS 15.4.1
- Subsystem:
Possible Solution
🤷 ActivityBigyaPradhan commented on Oct 2, 2025 This also stops feast ui from working. adarshsm commented on Jul 30, 2026 Root cause: ODFV loading eagerly deserializes the UDF. get_any_feature_view (sdk/python/feast/infra/registry/proto_registry_utils.py:151) calls OnDemandFeatureView.from_proto without skip_udf, which runs _parse_transformation_from_proto → Pandas/PythonTransformation.from_proto → dill.loads(body). So any registry read that resolves an ODFV — list, feast ui, get_historical_features — raises ModuleNotFoundError when a single ODFV's UDF imports a module that isn't present in the reading environment, even for operations that never execute the UDF.
The skip_udf path already exists (_parse_transformation_from_proto returns None when it's set, and list_all_feature_views threads it through — the write path uses it), but get_any_feature_view and the default read paths don't pass it, so they still crash.
A few directions, each a slightly different philosophy — wanted to check which you'd prefer before implementing:
- Per-FV resilience on read: catch a single ODFV's deserialization failure during registry reads, log a warning, and degrade just that view (keeping
body_text/udf_string for display) so one bad UDF doesn't break reads of everything else. Executing that specific ODFV still fails loudly.
- Extend
skip_udf to the read paths that never execute UDFs (feast ui, list, delete), consistent with the existing opt-in approach.
- Lazy deserialization: defer
dill.loads until the UDF is actually invoked.
(1) fixes the reported symptoms with the least surface area and no change to a working view's semantics; (2) stays closest to the current skip_udf design; (3) is the most thorough but the largest change. Happy to implement whichever direction you'd prefer.
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|