Azure / Azurite

A lightweight server clone of Azure Storage that simulates most of the commands supported by it with minimal dependencies
MIT License
1.83k stars 325 forks source link

Invalid Status message for BadRequest #1829

Open PrasantJillella opened 1 year ago

PrasantJillella commented 1 year ago

Which service(blob, file, queue, table) does this issue concern?

Table

Which version of the Azurite was used?

3.22.0

Where do you get Azurite? (npm, DockerHub, NuGet, Visual Studio Code Extension)

npm

What's the Node.js version?

v18.14.2

What problem was encountered?

When we try to delete a record and provide invalid Etag value in the delete request then a 400 Bad Request error gets throw as expected.

But when it comes to the Error Message, Previously when using Azure Storage Emulator the message returned was: "0:The etag value 'MalformedETag' specified in one of the request headers is not valid. Please make sure only one etag value is specified and is valid." Now when using Azurite the message returned is: '1:' which does not seem to be correct.

Steps to reproduce the issue?

-> Insert a record in table. -> Try deleting the same record from table but provide invalid Etag value in the delete request. value provided by me for etag is "MalformedETag"

If possible, please provide the debug log using the -d parameter, replacing \<pathtodebuglog> with an appropriate path for your OS, or review the instructions for docker containers:

    info: HandlerMiddleware: DeserializedParameters={"version":"2018-03-28","options":{"requestId":"902cd6bd-a965-4ef1-820d-e36cc9c92013","dataServiceVersion":"3.0;"},"multipartContentType":"multipart/mixed; boundary=batch_82445a3b-2dd3-426d-848d-81cb7a61ec69","contentLength":1586,"body":"ReadableStream"}

    debug: TableHandler:batch() Raw request string is "--batch_82445a3b-2dd3-426d-848d-81cb7a61ec69\r\nContent-Type: multipart/mixed; boundary=changeset_32c83aa7-1a3b-4892-8473-c9a18f163bb8\r\n\r\n--changeset_32c83aa7-1a3b-4892-8473-c9a18f163bb8\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\nDELETE [http://127.0.0.1:10002/devstoreaccount1/TableName(PartitionKey='3a0829a3-ae7a-493b-bbc9-eebafa0cd40e',RowKey='d326e5b3-dfba-48bd-9d27-57686d93d8e4')](http://127.0.0.1:10002/devstoreaccount1/TableName(PartitionKey=%273a0829a3-ae7a-493b-bbc9-eebafa0cd40e%27,RowKey=%27d326e5b3-dfba-48bd-9d27-57686d93d8e4%27)) HTTP/1.1\r\nAccept: application/json;odata=minimalmetadata\r\nContent-Type: application/json\r\nDataServiceVersion: 3.0;\r\nIf-Match: W/\"datetime'2023-03-08T12%3A25%3A00.4743732Z'\"\r\n\r\n--changeset_32c83aa7-1a3b-4892-8473-c9a18f163bb8\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\nDELETE [http://127.0.0.1:10002/devstoreaccount1/TableName(PartitionKey='3a0829a3-ae7a-493b-bbc9-eebafa0cd40e',RowKey='115d0398-6987-467c-8a00-9fb8cad66968')](http://127.0.0.1:10002/devstoreaccount1/TableName(PartitionKey=%273a0829a3-ae7a-493b-bbc9-eebafa0cd40e%27,RowKey=%27115d0398-6987-467c-8a00-9fb8cad66968%27)) HTTP/1.1\r\nAccept: application/json;odata=minimalmetadata\r\nContent-Type: application/json\r\nDataServiceVersion: 3.0;\r\nIf-Match: MalformedETag\r\n\r\n--changeset_32c83aa7-1a3b-4892-8473-c9a18f163bb8\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\nDELETE [http://127.0.0.1:10002/devstoreaccount1/TableName(PartitionKey='3a0829a3-ae7a-493b-bbc9-eebafa0cd40e',RowKey='fe52aac3-1b4c-46d5-b079-f36393dc4aee')](http://127.0.0.1:10002/devstoreaccount1/TableName(PartitionKey=%273a0829a3-ae7a-493b-bbc9-eebafa0cd40e%27,RowKey=%27fe52aac3-1b4c-46d5-b079-f36393dc4aee%27)) HTTP/1.1\r\nAccept: application/json;odata=minimalmetadata\r\nContent-Type: application/json\r\nDataServiceVersion: 3.0;\r\nIf-Match: W/\"datetime'2023-03-08T12%3A25%3A00.4743737Z'\"\r\n\r\n--changeset_32c83aa7-1a3b-4892-8473-c9a18f163bb8--\r\n--batch_82445a3b-2dd3-426d-848d-81cb7a61ec69--\r\n"
    2023-03-08T12:27:13.812Z 2f266c87-fd46-4452-bba6-52636f94e526 debug: TableHandler:batch() Raw response string is "--batchresponse_82445a3b-2dd3-426d-848d-81cb7a61ec69\r\nContent-Type: multipart/mixed; boundary=changesetresponse_32c83aa7-1a3b-4892-8473-c9a18f163bb8\r\n\r\n--changesetresponse_32c83aa7-1a3b-4892-8473-c9a18f163bb8\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\nHTTP/1.1 400 Bad Request\r\nContent-ID: 2\r\nDataServiceVersion: 3.0;\r\nContent-Type: application/json;odata=minimalmetadata;charset=utf-8\r\n\r\n{\"odata.error\":{\"code\":\"InvalidOperation\",\"message\":{\"lang\":\"en-US\",\"value\":\"1:\\nRequestId:2f266c87-fd46-4452-bba6-52636f94e526\\nTime:2023-03-08T12:27:13.811Z\"}}}\r\n--changesetresponse_32c83aa7-1a3b-4892-8473-c9a18f163bb8--\r\n--batchresponse_82445a3b-2dd3-426d-848d-81cb7a61ec69--\r\n"

Please be sure to remove any PII or sensitive information before sharing!
The debug log will log raw request headers and bodies, so that we can replay these against Azurite using REST and create tests to validate resolution.

Have you found a mitigation/solution?

No

blueww commented 1 year ago

@edwin-huber Do you have any comments for the table batch delete issue?

@PrasantJillella Normally, your code should be based on the storage server returned error status code, instead of error message. Since the error message might not be so stable, and can change. Besides that, for the "0:" or "1:" in the error message, the number is the index of the failed operation (base 0). Like for "1:", the failed operation is the 2nd operation in the batch, so the index is 1.

PrasantJillella commented 1 year ago

Hi

I noticed that ErrorCode was not provided in this case, instead I see that there was ExtendedErrorInformation.ErrorCode present. ExtendedErrorInformation.ErrorCode = "InvalidOperation"

I was curious about this relation b/w ErrorCode and ExtendedErrorInformation.ErrorCode: Are these two interchangeable, I mean if one is empty then does the other always populate in case of an exception. Also can we consider both of them to provide the same information? Also is there a case where both provide values that are different?

I did go through ExtendedErrorInformation.ErrorCode documentation, but it does not answer this question of my so wanted to check if you had any idea.

blueww commented 1 year ago

@PrasantJillella

For "ExtendedErrorInformation.ErrorCode", I think you get it from SDK interface, since Azurite doesn't return error in this structure. You might should check with the SDK owner to see how they parse the "ExtendedErrorInformation.ErrorCode", and know the relationship between "ExtendedErrorInformation.ErrorCode" and "ErrorCode".