[ISSUE] `apierr.GetAPIError` does not unmarshal `ErrorCode` correctly
Description
apierr.GetAPIError does not unmarshal ErrorCode correctly
Reproduction
Below is a simplified version of parseErrorFromResponse
func main() {
myError := apierr.APIError{
ErrorCode: "RESOURCE_DOES_NOT_EXIST",
Message: "Path (/Users/abc) doesn't exist.",
}
b, err := json.Marshal(myError)
if err != nil {
panic(err)
}
print(b)
var errorBody struct {
ErrorCode any `json:"error_code,omitempty"`
Message string `json:"message,omitempty"`
}
err = json.Unmarshal(b, &errorBody)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", errorBody)
}
Expected behavior errorBody should be populated with ErrorCode & Message, however, ErrorCode is nil in this case
{ErrorCode:<nil> Message:Path (/Users/abc) doesn't exist.}
Hi @nkvuong,
apierr.GetAPIError does not unmarshal ErrorCode correctly
Do you have an example of an input/ouput pair for apierr.GetAPIError that produces the incorrect behavior you are referring to?
it happened in the failed test in this PR from TF provider - https://github.com/databricks/terraform-provider-databricks/pull/3832. The PR simply replaces the deprecated struct in TF with the Go SDK equivalent.
For example TestResourceUserDelete_NonExistingDir should produce no error due to the error handling in this line
https://github.com/databricks/terraform-provider-databricks/blob/main/scim/resource_user.go#L156. However, apierr.IsMissing is returning false for this test case, because the ErrorCode was not unmarshaled correctly.
Since the only change is replacing the structs, we can simply compare the 2 structs, and the difference is the missing field tags
https://github.com/databricks/terraform-provider-databricks/blob/8d628d198523beb0beb379a94661d31ac8c3b3b7/common/apierr.go#L9-L17
https://github.com/databricks/databricks-sdk-go/blob/9bbc945278e8d97ae011a90dbd331c6e90180799/apierr/errors.go#L30-L39
I see, thanks!
I think the core of the problem you're facing is that apierr.APIError is not meant to be a substitute for common.APIErrorBody. Rather, it is the "higher level" object that is returned by the SDK service clients, not the SDK HTTP client. Making a clear distinction between these two levels is the reason why the parsing struct was made anonymous in parseErrorFromResponse.
It seems that resource_user.go is not using the SDK service client but the HTTP client directly. Therefore, we cannot use apierr.IsMissing on the returned error given that the HTTP client is not returning an api.APIError to begin with.
I think there's two ways we can resolve this:
- A: Change the terraform code to use the service client instead of the HTTP client — and then truly deprecate
common.APIErrorBody. - B: Implement your own
IsMissingfunction that would take acommon.APIErrorBodystruct as parameter.
What do you think?
Closing this issue as "work as expected"