Title: DynamoDB tags may be removed after repeated store.apply() due to asynchronous UntagResource / TagResource operations · Issue #6418 · feast-dev/feast · GitHub
Open Graph Title: DynamoDB tags may be removed after repeated store.apply() due to asynchronous UntagResource / TagResource operations · Issue #6418 · feast-dev/feast
X Title: DynamoDB tags may be removed after repeated store.apply() due to asynchronous UntagResource / TagResource operations · Issue #6418 · feast-dev/feast
Description: Expected Behavior When store.apply() is executed multiple times against a Feast registry configured with DynamoDB as the online store, table tags should remain stable and idempotent. Repeated executions of: store.apply([..]) should not m...
Open Graph Description: Expected Behavior When store.apply() is executed multiple times against a Feast registry configured with DynamoDB as the online store, table tags should remain stable and idempotent. Repeated execu...
X Description: Expected Behavior When store.apply() is executed multiple times against a Feast registry configured with DynamoDB as the online store, table tags should remain stable and idempotent. Repeated execu...
Opengraph URL: https://github.com/feast-dev/feast/issues/6418
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"DynamoDB tags may be removed after repeated store.apply() due to asynchronous UntagResource / TagResource operations","articleBody":"## Expected Behavior \nWhen store.apply() is executed multiple times against a Feast registry configured with DynamoDB as the online store, table tags should remain stable and idempotent.\n\nRepeated executions of:\n\n`store.apply([..])`\n\nshould not modify the final tag state when no configuration changes have occurred.\n\nThe DynamoDB tables should consistently retain the configured tags after every execution.\n## Current Behavior\n\nFeast's DynamoDB online store implementation updates tags by:\n\n1. Reading existing tags (ListTagsOfResource)\n2. Removing all existing tags (UntagResource)\n3. Recreating all configured tags (TagResource)\n\nHowever, DynamoDB documents both TagResource and UntagResource as asynchronous and eventually consistent operations.\n\nBecause Feast invokes TagResource immediately after UntagResource without waiting for propagation, repeated executions can leave tables without tags.\n\nObserved behavior:\n\n```\napply #1 -\u003e tags present\napply #2 -\u003e tags missing\napply #3 -\u003e tags present\napply #4 -\u003e tags missing\n```\n\nAdding a delay between `UntagResource` and `TagResource` eliminates the issue.\n\n## Steps to reproduce\n\n### Feast configuration\n\nConfigure DynamoDB as the online store with table tags enabled:\n\n```\nonline_store:\n type: dynamodb\n region: eu-west-1\n\n tags:\n project: test-fstore\n```\n### Apply definitions repeatedly\n```\nstore.apply([...])\n```\n### Observe tag state\n\nRun repeatedly:\n\n```\naws dynamodb list-tags-of-resource \\\n --resource-arn \u003ctable-arn\u003e\n\n```\nTags may disappear after an apply execution even though Feast issued a successful TagResource request.\n\n### Additional debugging\n\nInstrumenting `_update_tags()` shows:\n\n```\ncurrent_tags = dynamodb_client.list_tags_of_resource(...)\n\ndynamodb_client.untag_resource(...)\n\n# immediately after untag\nlist_tags_of_resource() -\u003e still returns previous tags\n\ntime.sleep(10)\n\nlist_tags_of_resource() -\u003e returns []\n\ndynamodb_client.tag_resource(...)\n\n# immediately after tag\nlist_tags_of_resource() -\u003e still returns []\n\ntime.sleep(10)\n\nlist_tags_of_resource() -\u003e returns expected tags\n```\n\nThis matches DynamoDB documentation stating that tag operations are eventually consistent.\n\n## Specifications\n\n- Version: Feast 0.63.0\n- Online Store: DynamoDB\n\n## Possible Solution\n\nThe DynamoDB online store implementation should not assume that `UntagResource` has completed when the API call returns.\nPotential fixes:\nOption 1\nWait until tag removal is visible before issuing `TagResource`.\nExample:\n```\nuntag_resource(...)\nwhile list_tags_of_resource(...):\n time.sleep(1)\ntag_resource(...)\n```\nOption 2\nAvoid deleting and recreating all tags.\nInstead:\n\n\n- Compute the tag diff\n- Add/update only changed tags\n- Remove only obsolete tags\n\n\nThis would avoid the race condition entirely and reduce API calls.\nRelevant AWS documentation\n\nAWS DynamoDB documentation for UntagResource:\n\n\n\u003e UntagResource is an asynchronous operation.\n\n\n\u003e The application or removal of tags using TagResource and UntagResource APIs is eventually consistent.\n\n\n\u003e ListTagsOfResource API will only reflect the changes after a few seconds.\n\nThis behavior appears incompatible with the current implementation that performs `UntagResource` immediately followed by `TagResource` without waiting for propagation.","author":{"url":"https://github.com/parodin","@type":"Person","name":"parodin"},"datePublished":"2026-05-19T10:44:05.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/6418/feast/issues/6418"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:2abbc8d5-0dd2-6be8-12fa-15d5dd6f8910 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 97CE:1B6F9B:1691B7B:1F51EF8:6A4DF41E |
| html-safe-nonce | 58e7c5067875e30c77666e3204fef240a05e6857d9332923f799393e1954c52f |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5N0NFOjFCNkY5QjoxNjkxQjdCOjFGNTFFRjg6NkE0REY0MUUiLCJ2aXNpdG9yX2lkIjoiODA2MDk5NDc3MjY4NzI1NDU1OCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 191a282da5f4ac349f2a74a94f0e065f6814013a39488b70c21945ef76fd25e3 |
| hovercard-subject-tag | issue:4476676198 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/feast-dev/feast/6418/issue_layout |
| twitter:image | https://opengraph.githubassets.com/5ded29193255abec09b0cc91fb40ba231644bc4d21bad1d12e2b540b50853b7c/feast-dev/feast/issues/6418 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/5ded29193255abec09b0cc91fb40ba231644bc4d21bad1d12e2b540b50853b7c/feast-dev/feast/issues/6418 |
| og:image:alt | Expected Behavior When store.apply() is executed multiple times against a Feast registry configured with DynamoDB as the online store, table tags should remain stable and idempotent. Repeated execu... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | parodin |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5818716c93c6a2925b815402541a32814e43a7b1261c322b0c2df75224289566 |
| turbo-cache-control | no-preview |
| go-import | github.com/feast-dev/feast git https://github.com/feast-dev/feast.git |
| octolytics-dimension-user_id | 57027613 |
| octolytics-dimension-user_login | feast-dev |
| octolytics-dimension-repository_id | 161133770 |
| octolytics-dimension-repository_nwo | feast-dev/feast |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 161133770 |
| octolytics-dimension-repository_network_root_nwo | feast-dev/feast |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | f4bb89367ca678f057d79b1abc45d6675b1bd5b2 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width