Description
Summary
During a table's DELETING window the service refuses TagResource and UntagResource and serves ListTagsOfResource; ExtendDB answers differently on every backend.
Request during DELETING |
Service (measured 2026-10-25, us-east-1) | ExtendDB main 744ea29 |
ExtendDB after #550 (PostgreSQL, SQLite) |
|---|---|---|---|
TagResource |
400 ResourceInUseException Attempt to change a resource which is still in use: Table is being deleted: <name> |
400 ResourceNotFoundException Requested resource not found: ResourceArn: <arn> not found |
200 |
UntagResource |
same | same | 200 |
ListTagsOfResource |
200 with the tags | same ResourceNotFoundException |
200 with the tags |
MongoDB and Cassandra keep the main answers after #550.
Cause
crates/engine/src/tagging.rs checks the table's existence through table_key_info and maps TableNotFound to ResourceNotFoundException. On main every backend's key-info read maps a DELETING row to TableNotFound; #550 makes PostgreSQL and SQLite read it as found (so the data plane is served, as the service does), and the tag path inherits that.
A TagResource accepted in the window writes an unconditioned tag row. On PostgreSQL the poller deletes the ARN's tag rows before the catalog row, so a tag written between those two statements survives the table and is inherited by the next table of that name. The measured sequence (tag, then drop) left no row behind; the hazard is the interleaving.
Fix shape
Refuse TagResource and UntagResource on a DELETING row with the TableBeingDeleted sentence #550 introduced (the tag path needs the table's status, which TableKeyInfo does not carry; a describe_table read or a status field on the key info), and serve ListTagsOfResource. One wire row per request, dual-target, on the held-window fixture tests/python/test_deleting_window_control_plane.py uses.
Found while reviewing #505.
Activity
fix: answer TTL and tag calls during a table's DELETING window as the…