← 返回首页
`ValueError: The truth value of an empty array is ambiguous` during materialization · Issue #6255 · feast-dev/feast · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

ValueError: The truth value of an empty array is ambiguous during materialization #6255

New issue
New issue

Description

Expected Behavior

feast materialize should complete successfully even when the source DataFrame
contains an empty numpy array (np.array([])) in a scalar feature column.
The empty array should be treated as a null / missing value and produce an empty
ProtoValue(), consistent with how None and np.nan are already handled.

Current Behavior

feast materialize crashes with:

ValueError: The truth value of an empty array is ambiguous. Use `array.size > 0` to check that an array is not empty.

Full stack trace:

Traceback (most recent call last): File "/opt/app-root/bin/feast", line 10, in <module> sys.exit(cli()) ^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/click/core.py", line 1485, in __call__ return self.main(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/click/core.py", line 1406, in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/click/core.py", line 1873, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/click/core.py", line 1269, in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/click/core.py", line 824, in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/click/decorators.py", line 34, in new_func return f(get_current_context(), *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/feast/cli/cli.py", line 393, in materialize_command store.materialize( File "/opt/app-root/lib64/python3.11/site-packages/feast/feature_store.py", line 1816, in materialize provider.materialize_single_feature_view( File "/opt/app-root/lib64/python3.11/site-packages/feast/infra/passthrough_provider.py", line 456, in materialize_single_feature_view raise e File "/opt/app-root/lib64/python3.11/site-packages/feast/infra/compute_engines/local/compute.py", line 84, in _materialize_one plan.execute(context) File "/opt/app-root/lib64/python3.11/site-packages/feast/infra/compute_engines/dag/plan.py", line 51, in execute output = node.execute(context) ^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/feast/infra/compute_engines/local/nodes.py", line 274, in execute rows_to_write = _convert_arrow_to_proto( ^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/feast/utils.py", line 281, in _convert_arrow_to_proto return _convert_arrow_fv_to_proto(table, feature_view, join_keys) # type: ignore[arg-type] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/feast/utils.py", line 298, in _convert_arrow_fv_to_proto proto_values_by_column = { ^ File "/opt/app-root/lib64/python3.11/site-packages/feast/utils.py", line 299, in <dictcomp> column: python_values_to_proto_values( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/feast/type_map.py", line 840, in python_values_to_proto_values proto_values = _python_value_to_proto_value(value_type, values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/app-root/lib64/python3.11/site-packages/feast/type_map.py", line 772, in _python_value_to_proto_value elif not pd.isnull(value): ValueError: The truth value of an empty array is ambiguous. Use `array.size > 0` to check that an array is not empty.

The root cause is in sdk/python/feast/type_map.py,
function _convert_scalar_values_to_proto (around line 968):

# Generic scalar conversion out = [] for value in values: if isinstance(value, ProtoValue): out.append(value) elif not pd.isnull(value): # ← crashes here out.append(ProtoValue(**{field_name: func(value)})) else: out.append(ProtoValue())

pd.isnull() is vectorised: when value is a numpy array (including an empty
one), it returns a numpy array of booleans instead of a scalar boolean. Applying
Python's not to that array raises ValueError. The same pattern exists a few lines
above in the ValueType.BOOL path (if not pd.isnull(value)).

Steps to reproduce

import numpy as np from feast.type_map import python_values_to_proto_values from feast.value_type import ValueType # A scalar column where one row contains an empty array python_values_to_proto_values([np.array([]), 1.0, 2.0], ValueType.DOUBLE) # → ValueError: The truth value of an empty array is ambiguous

Specifications

  • Version: v0.60.0 (also reproducible on main as of 2026-04-10)
  • Platform: Linux (Python 3.11), macOS (Python 3.11)
  • Subsystem: feast/type_map.py – _convert_scalar_values_to_proto

Possible Solution

The fix belongs in sdk/python/feast/type_map.py, specifically the generic scalar conversion loop at line 963–975 (elif not pd.isnull(value)).

Before calling not pd.isnull(value), check whether the value is array-like.
pd.isnull() is vectorised and returns an np.ndarray for array inputs, so
calling not on it raises ValueError. The fix must handle three sub-cases:

Value Expected outcome
Empty array (size == 0) null → ProtoValue()
Non-empty array containing any null null → ProtoValue()
Non-empty array with all valid data convert → ProtoValue(**{field_name: func(value)})
Plain scalar null null → ProtoValue()
Plain scalar non-null convert → ProtoValue(**{field_name: func(value)})
# Generic scalar conversion out = [] for value in values: if isinstance(value, ProtoValue): out.append(value) elif isinstance(value, np.ndarray) or ( hasattr(value, "__len__") and not isinstance(value, (str, bytes)) ): # Array-like value in a scalar column if hasattr(value, "size") and value.size == 0: # Empty numpy array – treat as null out.append(ProtoValue()) else: is_null = pd.isnull(value) if hasattr(is_null, "any"): # pd.isnull returned an array; null if any element is null out.append(ProtoValue() if is_null.any() else ProtoValue(**{field_name: func(value)})) elif not is_null: out.append(ProtoValue(**{field_name: func(value)})) else: out.append(ProtoValue()) elif not pd.isnull(value): out.append(ProtoValue(**{field_name: func(value)})) else: out.append(ProtoValue()) return out

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Footer

      © 2026 GitHub, Inc.