Skip to content

fix: Check duplicate names for feature view across types#5999

Merged
ntkathole merged 5 commits intofeast-dev:masterfrom
Prathap-P:featureview_name_collision
Mar 6, 2026
Merged

fix: Check duplicate names for feature view across types#5999
ntkathole merged 5 commits intofeast-dev:masterfrom
Prathap-P:featureview_name_collision

Conversation

@Prathap-P
Copy link
Contributor

@Prathap-P Prathap-P commented Feb 21, 2026

What this PR does / why we need it:

  • This PR enforces cross-type feature view name uniqueness to fix a bug (Enforce unique feature view names across all feature view types during apply #5995).
  • Previously, get_online_features resolved feature view names via get_any_feature_view, which checks registry tables in a fixed order: FeatureView → StreamFeatureView → OnDemandFeatureView.
  • If a project registered both a FeatureView and StreamFeatureView with the same name, every get_online_features call would silently return the FeatureView, even when the StreamFeatureView contained fresher data

Which issue(s) this PR fixes:

Fixes #5995

Misc


Open with Devin

@Prathap-P Prathap-P requested a review from a team as a code owner February 21, 2026 12:10
devin-ai-integration[bot]

This comment was marked as resolved.

@Prathap-P Prathap-P force-pushed the featureview_name_collision branch 4 times, most recently from 77cc24c to c299a71 Compare February 21, 2026 13:19
@Prathap-P Prathap-P changed the title check duplicate names for feature view across types fix: check duplicate names for feature view across types Feb 21, 2026
@Prathap-P Prathap-P changed the title fix: check duplicate names for feature view across types fix: Check duplicate names for feature view across types Feb 21, 2026

# Check StreamFeatureView before FeatureView since StreamFeatureView is a subclass
# Note: All getters raise FeatureViewNotFoundException (not type-specific exceptions)
if isinstance(feature_view, StreamFeatureView):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean it will call to retrieve feature view many times? Can we optimize it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, you're concerned that when creating 100 feature views, the apply_feature_view function calls the getters for the other two types each time. That results in 2 database calls per feature view — 200 total — and you’re wondering if we should optimize this part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HaoXuAI
I have a plan. We need to validate in two places:

  1. In the incoming request — ensure the new feature view name doesn’t exist in the other two types within the request (and vice versa).
  2. In the database — check against existing records (for the SQL registry case).

Currently, the cache util doesn’t have an exists function to check if a name is already in the registry. Even if it did, calling it 100 times wouldn’t be efficient.

So I’m planning to create a util function per feature view type that takes a list of names and a project, and checks that none of the names exist in the DB.

For example, if 50 feature views come in:

  • I’ll call the new util once with those 50 names against the stream and on-demand tables.
  • Do the same vice versa for the other types.

This way, instead of calling per feature view, we make only two DB calls per type.

That’s my current idea. Do you see any better optimization?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HaoXuAI I can go ahead to implement, if you find we are good with above logic 😄

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think that makes sense. Feel free to create a new issue for this. We can go with the current solution for now

@Prathap-P Prathap-P requested a review from HaoXuAI February 24, 2026 16:21
@ntkathole ntkathole force-pushed the featureview_name_collision branch from 3d8682d to 0332891 Compare February 28, 2026 15:36
f"More than one feature view with name {case_insensitive_fv_name} found. "
f"Please ensure that all feature view names are case-insensitively unique. "
f"It may be necessary to ignore certain files in your feature repository by using a .feastignore file."
if case_insensitive_fv_name in fv_by_name:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_validate_feature_views() in feature_store.py uses case-insensitive names (fv.name.lower()), while
_ensure_feature_view_name_is_unique() relies on the registry getters, which are typically case-sensitive. Worth aligning the behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntkathole Thanks for your comment.
On trying to work on that, I have a found an inconsistency (might be a potential issue).
I'm holding my progress on above issue, till I get clarified on this.

In current Feast master, FeatureStore.apply() behaves as an incremental upsert (not a full registry refresh): it validates only the objects in the current request and writes those objects, while existing unrelated records remain untouched. Because of this, duplicate-name protection is incomplete for previously registered objects—especially when names differ only by case (for example, existing driver and new Driver). The in-request validation checks only the incoming payload, and the SQL registry uniqueness constraints are per table and case-sensitive by default, so this scenario can pass and create ambiguous registry state. Expected behavior (per my understanding) is case-insensitive uniqueness for feature view names, so this appears to be a gap.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Prathap-P I think it's fine if you want to handle it separately and we keep scope of this PR for sql registry duplicate names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntkathole Solving the test cases took a lot of time, finally was able to fix it. Do you have any other points to discuss?

Copy link
Contributor Author

@Prathap-P Prathap-P Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know Devin is reporting these changes are not implemented in snowflake, but as you said to scope this pr to sql, ignoring it...

@Prathap-P Prathap-P force-pushed the featureview_name_collision branch from 4c5be75 to a2a0e29 Compare March 1, 2026 17:30
devin-ai-integration[bot]

This comment was marked as resolved.

@Prathap-P Prathap-P force-pushed the featureview_name_collision branch 2 times, most recently from c2acd43 to 7404904 Compare March 2, 2026 14:05
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@Prathap-P Prathap-P force-pushed the featureview_name_collision branch from 786b948 to 86781e9 Compare March 3, 2026 10:02
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

🐛 1 issue in files not directly in the diff

🐛 Cross-type uniqueness check missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272)

The PR adds _ensure_feature_view_name_is_unique to BaseRegistry and calls it from SqlRegistry.apply_feature_view (sdk/python/feast/infra/registry/sql.py:580), but the same call is missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272). This means the "defense-in-depth" cross-type name conflict check is not enforced when users use the Snowflake registry and directly call apply_feature_view.

Incomplete application of fix across registry implementations

The SnowflakeRegistry.apply_feature_view at sdk/python/feast/infra/registry/snowflake.py:261-272 does not call self._ensure_feature_view_name_is_unique(feature_view, project) before applying the feature view:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    fv_table_str = self._infer_fv_table(feature_view)
    fv_column_name = fv_table_str[:-1]
    return self._apply_object(...)

Compare with the updated SqlRegistry.apply_feature_view at sdk/python/feast/infra/registry/sql.py:577-585 which does call it:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    self._ensure_feature_view_name_is_unique(feature_view, project)  # added
    fv_table = self._infer_fv_table(feature_view)
    ...

Impact: Snowflake registry users who directly call apply_feature_view (bypassing feast apply) can still register a FeatureView and a StreamFeatureView with the same name, leading to the same silent data correctness bug (issue #5995) that this PR intends to fix.

View 8 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

🐛 1 issue in files not directly in the diff

🐛 Cross-type uniqueness check missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272)

The PR adds _ensure_feature_view_name_is_unique to BaseRegistry and calls it from SqlRegistry.apply_feature_view (sdk/python/feast/infra/registry/sql.py:580), but the same call is missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272). This means the "defense-in-depth" cross-type name conflict check is not enforced when users use the Snowflake registry and directly call apply_feature_view.

Incomplete application of fix across registry implementations

The SnowflakeRegistry.apply_feature_view at sdk/python/feast/infra/registry/snowflake.py:261-272 does not call self._ensure_feature_view_name_is_unique(feature_view, project) before applying the feature view:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    fv_table_str = self._infer_fv_table(feature_view)
    fv_column_name = fv_table_str[:-1]
    return self._apply_object(...)

Compare with the updated SqlRegistry.apply_feature_view at sdk/python/feast/infra/registry/sql.py:577-585 which does call it:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    self._ensure_feature_view_name_is_unique(feature_view, project)  # added
    fv_table = self._infer_fv_table(feature_view)
    ...

Impact: Snowflake registry users who directly call apply_feature_view (bypassing feast apply) can still register a FeatureView and a StreamFeatureView with the same name, leading to the same silent data correctness bug (issue #5995) that this PR intends to fix.

View 10 additional findings in Devin Review.

Open in Devin Review

@Prathap-P Prathap-P force-pushed the featureview_name_collision branch from d2972de to c299a71 Compare March 4, 2026 11:24
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

🐛 1 issue in files not directly in the diff

🐛 Cross-type uniqueness check missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272)

The PR adds _ensure_feature_view_name_is_unique to BaseRegistry and calls it from SqlRegistry.apply_feature_view (sdk/python/feast/infra/registry/sql.py:580), but the same call is missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272). This means the "defense-in-depth" cross-type name conflict check is not enforced when users use the Snowflake registry and directly call apply_feature_view.

Incomplete application of fix across registry implementations

The SnowflakeRegistry.apply_feature_view at sdk/python/feast/infra/registry/snowflake.py:261-272 does not call self._ensure_feature_view_name_is_unique(feature_view, project) before applying the feature view:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    fv_table_str = self._infer_fv_table(feature_view)
    fv_column_name = fv_table_str[:-1]
    return self._apply_object(...)

Compare with the updated SqlRegistry.apply_feature_view at sdk/python/feast/infra/registry/sql.py:577-585 which does call it:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    self._ensure_feature_view_name_is_unique(feature_view, project)  # added
    fv_table = self._infer_fv_table(feature_view)
    ...

Impact: Snowflake registry users who directly call apply_feature_view (bypassing feast apply) can still register a FeatureView and a StreamFeatureView with the same name, leading to the same silent data correctness bug (issue #5995) that this PR intends to fix.

View 13 additional findings in Devin Review.

Open in Devin Review

@Prathap-P Prathap-P force-pushed the featureview_name_collision branch from b7e9e68 to eac7fe0 Compare March 6, 2026 06:01
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

🐛 1 issue in files not directly in the diff

🐛 Cross-type uniqueness check missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272)

The PR adds _ensure_feature_view_name_is_unique to BaseRegistry and calls it from SqlRegistry.apply_feature_view (sdk/python/feast/infra/registry/sql.py:580), but the same call is missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272). This means the "defense-in-depth" cross-type name conflict check is not enforced when users use the Snowflake registry and directly call apply_feature_view.

Incomplete application of fix across registry implementations

The SnowflakeRegistry.apply_feature_view at sdk/python/feast/infra/registry/snowflake.py:261-272 does not call self._ensure_feature_view_name_is_unique(feature_view, project) before applying the feature view:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    fv_table_str = self._infer_fv_table(feature_view)
    fv_column_name = fv_table_str[:-1]
    return self._apply_object(...)

Compare with the updated SqlRegistry.apply_feature_view at sdk/python/feast/infra/registry/sql.py:577-585 which does call it:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    self._ensure_feature_view_name_is_unique(feature_view, project)  # added
    fv_table = self._infer_fv_table(feature_view)
    ...

Impact: Snowflake registry users who directly call apply_feature_view (bypassing feast apply) can still register a FeatureView and a StreamFeatureView with the same name, leading to the same silent data correctness bug (issue #5995) that this PR intends to fix.

View 12 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

🐛 1 issue in files not directly in the diff

🐛 Cross-type uniqueness check missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272)

The PR adds _ensure_feature_view_name_is_unique to BaseRegistry and calls it from SqlRegistry.apply_feature_view (sdk/python/feast/infra/registry/sql.py:580), but the same call is missing from SnowflakeRegistry.apply_feature_view (sdk/python/feast/infra/registry/snowflake.py:261-272). This means the "defense-in-depth" cross-type name conflict check is not enforced when users use the Snowflake registry and directly call apply_feature_view.

Incomplete application of fix across registry implementations

The SnowflakeRegistry.apply_feature_view at sdk/python/feast/infra/registry/snowflake.py:261-272 does not call self._ensure_feature_view_name_is_unique(feature_view, project) before applying the feature view:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    fv_table_str = self._infer_fv_table(feature_view)
    fv_column_name = fv_table_str[:-1]
    return self._apply_object(...)

Compare with the updated SqlRegistry.apply_feature_view at sdk/python/feast/infra/registry/sql.py:577-585 which does call it:

def apply_feature_view(
    self, feature_view: BaseFeatureView, project: str, commit: bool = True
):
    self._ensure_feature_view_name_is_unique(feature_view, project)  # added
    fv_table = self._infer_fv_table(feature_view)
    ...

Impact: Snowflake registry users who directly call apply_feature_view (bypassing feast apply) can still register a FeatureView and a StreamFeatureView with the same name, leading to the same silent data correctness bug (issue #5995) that this PR intends to fix.

View 13 additional findings in Devin Review.

Open in Devin Review

Copy link
Member

@ntkathole ntkathole left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Prathap-P

Signed-off-by: Prathap P <436prathap@gmail.com>
Signed-off-by: Prathap P <436prathap@gmail.com>
Signed-off-by: Prathap P <436prathap@gmail.com>
Signed-off-by: Prathap P <436prathap@gmail.com>
@ntkathole ntkathole force-pushed the featureview_name_collision branch from 7a20e7b to d7bac33 Compare March 6, 2026 12:03
@ntkathole ntkathole merged commit 95b9af8 into feast-dev:master Mar 6, 2026
20 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enforce unique feature view names across all feature view types during apply

3 participants