fix: Answer online requests that carry zero entity rows - #6820
Open
Daksha1611 wants to merge 2 commits into
Open
fix: Answer online requests that carry zero entity rows#6820Daksha1611 wants to merge 2 commits into
Daksha1611 wants to merge 2 commits into
Conversation
Daksha1611
requested review from
franciscojavierarceo,
haoxu0 and
ntkathole
and removed request for
a team
September 7, 2026 06:12
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #6820 +/- ##
==========================================
- Coverage 47.08% 47.08% -0.01%
==========================================
Files 419 419
Lines 51877 51872 -5
Branches 7525 7524 -1
==========================================
- Hits 24428 24424 -4
+ Misses 25700 25699 -1
Partials 1749 1749
*This pull request uses carry forward flags. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
Three empty-input shapes reached internal exceptions, and the feature server
turned each into an HTTP 500:
entity_rows=[] -> IndexError: list index out of range
entities={"driver_id": []} -> KeyError: Missing join key values for keys: []
entities={} -> KeyError: 'pop from an empty set'
The middle case is a well-formed request. The join key was supplied, it simply
has no values, which is what a caller sends when the upstream query matched
nothing that run.
get_online_features built its columnar dict from entity_rows[0] on both the
sync and async paths, so an empty list raised before anything else ran.
_validate_entity_values ended with set_of_row_lengths.pop(); for a mapping with
no columns the set is empty and pop() raised. Report zero rows instead.
_get_unique_entities treated a join key present with zero values the same as a
join key never supplied, even though the row-wise conversion just below it
already returns empty results for that case. Raise only when nothing at all was
supplied for the view, which leaves the existing behaviour intact: a partially
supplied key set still proceeds, and a caller that supplied nothing relevant
still errors with the same message listing the expected keys.
That error is now MissingJoinKeyValuesException, carrying HTTP 400 so the server
reports a client error rather than a 500. It subclasses KeyError as well, since
that is what this condition raised before and callers catch it.
Signed-off-by: Daksha1611 <mehtadaksha1611@gmail.com>
The guard was added to both get_online_features and its async twin, but only the sync one had a test. Without the fix the async case raises IndexError: list index out of range. Signed-off-by: Daksha1611 <mehtadaksha1611@gmail.com>
ntkathole
force-pushed
the
fix/empty-entity-rows
branch
from
September 9, 2026 11:29
99020ef to
f96b47b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does / why we need it:
Three empty-input shapes reached internal exceptions, and the feature server turned each
into an HTTP 500:
The middle case is a well-formed request: the join key was supplied, it simply holds
no values, which is what a caller sends when the upstream query matched nothing that run.
Three causes, fixed here:
get_online_featuresbuilt its columnar dict fromentity_rows[0]on both the syncand async paths, so an empty list raised before anything else ran.
_validate_entity_valuesended withset_of_row_lengths.pop(); for a mapping with nocolumns the set is empty and
pop()raised. It now reports zero rows._get_unique_entitiestreated a join key present with zero values the same as onenever supplied — even though the row-wise conversion immediately below it already
returns empty results for that case (
if not rowise: return (), (), 0). It now raisesonly when nothing at all was supplied for the view.
That last change is deliberately narrow, so existing behaviour is preserved: a partially
supplied key set still proceeds (covered by
test_get_unique_entities_missing_join_key_success),and a caller supplying nothing relevant still errors with the same message listing the
expected keys (covered by
test_get_unique_entities_missing_all_join_keys_error).The error is now
MissingJoinKeyValuesException, carrying HTTP 400 so the server reportsa client error rather than a 500. It subclasses
KeyErroras well, since that is whatthis condition raised before and callers catch it — so this is not a breaking change.
Resulting behaviour: join keys supplied but empty → 200 with an empty result and correct
feature-name metadata; nothing supplied → 400 naming the missing key.
Which issue(s) this PR fixes:
Fixes #6819
Checks
git commit -s)Testing Strategy
New
sdk/python/tests/unit/online_store/test_empty_entity_rows.py. Four of its fivetests fail on
master, reproducing all three symptoms above; the fifth asserts the newexception is still a
KeyErrorand carries 400.Full
sdk/python/tests/unit: 2612 passed, 24 skipped. The 6 failures and 28 errorsin that run are environmental and present on
mastertoo — PySpark worker/driver Pythonversion mismatch, a torch import, MongoDB testcontainers, and a missing CUDA library.
ruff check,ruff format --checkandmypyare clean on all changed files.Misc
An empty response was chosen over a 400 for the empty-but-present case, so batch-scoring
callers don't have to special-case "my filter matched nothing". It also lines up with
get_historical_featuresreturning an empty frame for a zero-rowentity_df. Happy toswitch to a 400 if maintainers prefer the stricter reading.