azure-sdk-for-net icon indicating copy to clipboard operation
azure-sdk-for-net copied to clipboard

[QUERY] FormRecognizer - Error Handling

Open wahyuen opened this issue 2 years ago • 6 comments

Library name and version

Azure.AI.FormRecognizer 4.0.0-beta,3

Query/Question

What is the expectations for consumers of the SDK in respect to processing and pulling out information when the service throws an Exception?

Currently, the SDK appears to throw a RequestFailedException but does not contain any InnerException. The meaningful part of the exception is currently buried under the Message property as a free text string, example as follows:

Invalid request.
Status: 400 (Bad Request)
ErrorCode: InvalidRequest

Content:
{"error":{"code":"InvalidRequest","message":"Invalid request.","innererror":{"code":"InvalidContent","message":"The file is corrupted or format is unsupported. Refer to documentation for the list of supported formats."}}}

Headers:
Transfer-Encoding: chunked
x-envoy-upstream-service-time: 506
apim-request-id: 073013c4-067e-4c31-b275-51cf645f1279
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Date: Mon, 28 Feb 2022 07:48:58 GMT
Content-Type: application/json; charset=utf-8

We would love to access the actual Content of the above message. We have currently manually performed string manipulation to pull that JSON structure out, however, it also appears that the Error class is marked as internal by the SDK and thus we cannot deserialize into this object. Instead, we have had to create a proxy object, effectively a mirror of the SDK Error class in order to look at this information.

Is there a recommended pattern that the team would suggest to handle this scenario better? Have I missed something in terms of casting/accessing something that would make our lives easier instead of having to write such custom error handling conditions?

Environment

❯ dotnet --info .NET SDK (reflecting any global.json): Version: 6.0.102 Commit: 02d5242ed7

Runtime Environment: OS Name: Windows OS Version: 10.0.19044 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\6.0.102\

Host (useful for support): Version: 6.0.2 Commit: 839cdfb0ec

wahyuen avatar Feb 28 '22 23:02 wahyuen

Label prediction was below confidence level 0.6 for Model:ServiceLabels: 'Cognitive - Form Recognizer:0.2236037,Storage:0.19320105,Service Bus:0.076246895'

azure-sdk avatar Feb 28 '22 23:02 azure-sdk

Thank you for your feedback. Tagging and routing to the team member best able to assist.

jsquire avatar Mar 01 '22 16:03 jsquire

Bump, is there any guidance from the team regarding this issue?

wahyuen avatar Jul 22 '22 06:07 wahyuen

Hello @wahyuen, and apologies for the delay.

As you noted, the SDK does not expose an inner error object, and this is intentional. According to the Azure API guidelines, only the HTTP status code and the top-level error code are part of the API's contract that cannot change between versions. This means that there's no guarantee from the service that inner error details or error messages will stay the same. We cannot introduce breaking changes in the SDK, so we only expose the parts of the error payload that are safe for customers to rely on. Everything else is only surfaced via the Message property to aid diagnosability/debugging.

To answer your question, we recommend not relying on the contents of the Message property in your code since it's not guaranteed to have the same behavior across service versions.

Only if possible, could you share why you need the inner error object during runtime? If we get strong customer feedback for a particular scenario, we could provide tools to help with that in the future.

kinelski avatar Jul 22 '22 17:07 kinelski

@kinelski part of our confusion currently stems from an issue where the original request has actually been submitted successfully, but subsequently returned an InternalServerError

We had hoped to follow the guidance found here

image

and hoped to have some exception handling in our code to execute retries and other processing.

What we have found is that in this case we have actually been returned a HTTP 200 code, and are currently performing a message.Contains("InternalServerError") to catch this particular case. We had hoped to rely on the status codes or other parts of the exception to help better identify what has gone wrong.

eg. catch (RequestFailedExcection e) when (e.Status == (int)HttpStatusCode.InternalServerError)

wahyuen avatar Jul 22 '22 21:07 wahyuen

@wahyuen From my understanding, you're updating the status of a long-running operation with UpdateStatus or WaitForCompletion and getting an exception when the long-running operation fails. The HTTP 200 code is expected since you could successfully get the updated operation status, but the operation itself failed so our SDK throws an exception.

Unfortunately, for the reasons described in my previous reply, we currently don't have plans of exposing the inner error details in the SDK, so checking the error message with Contains could be the best approach for your scenario. If we receive enough feedback on this area, we might add something in the SDK to assist.

Alternately, you could call GetRawResponse in the operation object and parse the raw JSON response in your code, but this demands more work than your current string approach.

Please let me know if you need further assistance.

kinelski avatar Aug 09 '22 21:08 kinelski

Hi, we're sending this friendly reminder because we haven't heard back from you in 7 days. We need more information about this issue to help address it. Please be sure to give us your input. If we don't hear back from you within 14 days of this comment the issue will be automatically closed. Thank you!

ghost avatar Aug 17 '22 02:08 ghost

@kinelski does how the SDK handles this not pose a bit of a contradiction to the statement you are making regarding the 200 response code?

I understand what you are saying in terms of the UpdateStatus call succeeding, therefore the 200, but in that case, should the SDK not throw an Exception at all? By the above statement, since UpdateStatus has succeeded, would it not be the expectation that the user then interrogates the 'message' that is returned from UpdateStatus to indicate the original request has failed processing?

I guess if we reverse the logic, why does UpdateStatus throw an exception if indeed the call itself has succeeded?

wahyuen avatar Aug 17 '22 02:08 wahyuen

@kinelski is this still a valid concern.

pallavit avatar Dec 19 '23 01:12 pallavit

Hi @wahyuen, we deeply appreciate your input into this project. Regrettably, this issue has remained inactive for over 2 years, leading us to the decision to close it. We've implemented this policy to maintain the relevance of our issue queue and facilitate easier navigation for new contributors. If you still believe this topic requires attention, please feel free to create a new issue, referencing this one. Thank you for your understanding and ongoing support.

github-actions[bot] avatar Mar 04 '24 18:03 github-actions[bot]

Hi @wahyuen, we deeply appreciate your input into this project. Regrettably, this issue has remained inactive for over 2 years, leading us to the decision to close it. We've implemented this policy to maintain the relevance of our issue queue and facilitate easier navigation for new contributors. If you still believe this topic requires attention, please feel free to create a new issue, referencing this one. Thank you for your understanding and ongoing support.

github-actions[bot] avatar Apr 03 '24 18:04 github-actions[bot]