Azurite
Azurite copied to clipboard
Azurite returns duplicate odata.etag in table rows for table cloned with Azure Storage Explorer
Which service(blob, file, queue, table) does this issue concern?
table
Which version of the Azurite was used?
3.17.1
Where do you get Azurite? (npm, DockerHub, NuGet, Visual Studio Code Extension)
npm via Rider Azure plugin
What's the Node.js version?
12.18.3
What problem was encountered?
Duplicate property odata.etag
found in serialized json response after querying on RowKey
. This leads to a System.Private.CoreLib: Exception while executing function: (...). System.Private.CoreLib: An item with the same key has already been added. Key: odata.etag.
in Azure.Data.Tables v12.5.0.
Partial stack trace:
Function '... (Activity)' failed with an error. Reason: System.ArgumentException: An item with the same key has already been added. Key: odata.etag
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at Azure.Data.Tables.Models.TableEntityQueryResponse.DeserializeTableEntityQueryResponse(JsonElement element)
at Azure.Data.Tables.TableRestClient.QueryEntitiesAsync(String table, Nullable`1 timeout, String nextPartitionKey, String nextRowKey, QueryOptions queryOptions, CancellationToken cancellationToken)
at Azure.Data.Tables.TableClient.<>c__DisplayClass49_0`1.<<QueryAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Azure.Core.PageableHelpers.FuncAsyncPageable`1.AsPages(String continuationToken, Nullable`1 pageSizeHint)+MoveNext()
at Azure.Core.PageableHelpers.FuncAsyncPageable`1.AsPages(String continuationToken, Nullable`1 pageSizeHint)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
at Azure.AsyncPageable`1.GetAsyncEnumerator(CancellationToken cancellationToken)+MoveNext()
at Azure.AsyncPageable`1.GetAsyncEnumerator(CancellationToken cancellationToken)+MoveNext()
at Azure.AsyncPageable`1.GetAsyncEnumerator(CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
Steps to reproduce the issue?
- Start Azurite
- Clone a table with Microsoft Azure Storage Explorer v1.23.1
- Query the cloned table in code (C#) using Azure.Data.Tables v12.5.0
Extract from Azurite debug log, trimmed:
2022-06-10T06:36:18.665Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: TableStorageContextMiddleware: RequestMethod=GET RequestURL=http://127.0.0.1/devstoreaccount1/Office365UserDetails()?$format=application%2Fjson%3Bodata%3Dminimalmetadata&$filter=%28%28PartitionKey%20eq%20%27acme%27%29%20and%20%28RowKey%20ge%20%272022-02-13%27%29%29%20and%20%28RowKey%20lt%20%272022-02-14%27%29 RequestHeaders:{"host":"127.0.0.1:10002","x-ms-version":"2019-02-02","dataserviceversion":"3.0","accept":"application/json; odata=minimalmetadata","x-ms-client-request-id":"4a9abf9d-2b33-4929-a11b-545089905dfb","x-ms-return-client-request-id":"true","user-agent":"azsdk-net-Data.Tables/12.5.0 (.NET 6.0.4; Microsoft Windows 10.0.19044)","x-ms-date":"Fri, 10 Jun 2022 06:36:18 GMT","authorization":"SharedKeyLite devstoreaccount1:cwl6q0C7cMOwgwWJoYRcdtf3q88w3xILIOD48rtGNhI="} ClientIP=127.0.0.1 Protocol=http HTTPVersion=1.1
2022-06-10T06:36:18.665Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 debug: tableStorageContextMiddleware: Dispatch pattern string: /Office365UserDetails()
2022-06-10T06:36:18.665Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: tableStorageContextMiddleware: Account=devstoreaccount1 tableName=Office365UserDetails
2022-06-10T06:36:18.665Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 verbose: DispatchMiddleware: Dispatching request...
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: DispatchMiddleware: Operation=Table_QueryEntities
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 verbose: AuthenticationMiddlewareFactory:createAuthenticationMiddleware() Validating authentications.
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: TableSharedKeyLiteAuthenticator:validate() Start validation against account shared key authentication.
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: TableSharedKeyLiteAuthenticator:validate() [STRING TO SIGN]:"Fri, 10 Jun 2022 06:36:18 GMT\n/devstoreaccount1/devstoreaccount1/Office365UserDetails()"
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: TableSharedKeyLiteAuthenticator:validate() Calculated authentication header based on key1: SharedKeyLite devstoreaccount1:cwl6q0C7cMOwgwWJoYRcdtf3q88w3xILIOD48rtGNhI=
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: TableSharedKeyLiteAuthenticator:validate() Signature 1 matched.
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 verbose: DeserializerMiddleware: Start deserializing...
2022-06-10T06:36:18.666Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: HandlerMiddleware: DeserializedParameters={"options":{"queryOptions":{"format":"application/json;odata=minimalmetadata","filter":"((PartitionKey eq 'acme') and (RowKey ge '2022-02-13')) and (RowKey lt '2022-02-14')"},"requestId":"4a9abf9d-2b33-4929-a11b-545089905dfb","dataServiceVersion":"3.0"},"version":"2019-02-02"}
2022-06-10T06:36:18.684Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 debug: TableHandler:queryEntities() Raw response string is "{\"odata.metadata\":\"http://127.0.0.1:10002/devstoreaccount1/$metadata#Tables/@Element\",\"value\":[{\"odata.etag\":\"W/\\\"datetime'2022-06-10T06%3A21%3A42.279353Z'\\\"\",\"PartitionKey\":\"acme\",\"RowKey\":\"2022-02-13:[email protected]\",\"odata.etag\":\"W/\\\"datetime'2022-06-09T10%3A28%3A59.435654Z'\\\"\",\"ReportDate\":\"2022-02-13\",\"CustomerId\":\"acme\",\"ReportRefreshDate\":\"2022-02-13\",\"UserPrincipalName\":\"[email protected]\"}]}"
2022-06-10T06:36:18.684Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 verbose: SerializerMiddleware: Start serializing...
2022-06-10T06:36:18.684Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: Serializer: Start returning stream body.
2022-06-10T06:36:18.687Z 7653d0fa-125c-49f1-ace1-4d0d93cac7e4 info: EndMiddleware: End response. TotalTimeInMS=22 StatusCode=200 StatusMessage=OK Headers={"server":"Azurite-Table/3.17.1","content-type":"application/json;odata=minimalmetadata","x-ms-client-request-id":"4a9abf9d-2b33-4929-a11b-545089905dfb","x-ms-request-id":"7653d0fa-125c-49f1-ace1-4d0d93cac7e4","x-ms-version":"2021-06-08","date":"Fri, 10 Jun 2022 06:36:18 GMT"}
The relevant details are in the raw response string, formatted. Property odata.etag
found twice:
[
{
"odata.etag": "W/\"datetime'2022-06-10T06%3A21%3A42.279353Z'\"",
"PartitionKey": "acme",
"RowKey": "2022-02-13:[email protected]",
"odata.etag": "W/\"datetime'2022-06-09T10%3A28%3A59.435654Z'\"",
"ReportDate": "2022-02-13",
"CustomerId": "acme",
"ReportRefreshDate": "2022-02-13",
"UserPrincipalName": "[email protected]"
}
]
Have you found a mitigation/solution?
No
Workaround is to touch/update the copied rows in local storage because it "resets" the etag value to a non duplicate. But this works only via storage explorer.
Also happens if you "copy table" from one account and then "paste table" into the Azurite hosted instance.
I have encountered similar issue with new @azure/data-tables library for node. This new library returns etag as a part of entity like any other property but then by default it is also send in updates. Old emulator or production service just ignores etag property, but Azurite seems to save it. In subsequent updates you start to get 409 if you set etags to match. To get it working properly you have to remove etag from entity but it is not required on production servers.
This is really the same issue, as i think Azure Storage Explorer uses new @azure/data-tables nodejs library under the hood.
Work around that worked for me: Use export to file and then import into the new table instead of using clone or copy/paste in Storage Explorer