OpenAPI Spec Bug

I’m working with the CRM API using a client library generated from HubSpot’s OpenAPI v3.0.1 spec. I called an endpoint with incorrect data, and as expected the endpoint returned an error. However, the generated client library failed to parse the error into it’s error structures, and thus it returned that error (the fact that it’s error structures did not match the error response) instead of the error that indicated I provided bad data. I believe this indicates there’s a mismatch between the endpoint’s error response and the OpenAPI spec for the endpoints response, which would be a bug in either the OpenAPI spec, or the endpoint’s response.

Specifically, the BatchResponsePublicAssociationMultiWithErrors item in the spec is not compatible with the actual 207 response I got from calling the

Postcrmv3associationsFromObjectTypeToObjectTypebatchcreateCreateWithResponse method.

The JSON body of the endpoint’s response I received was:

{
 "status": "COMPLETE",
 "results": [],
 "numErrors": 1,
 "errors": [
 {
 "status": "error",
 "category": "VALIDATION_ERROR",
 "subCategory": "crm.associations.INVALID_ASSOCIATION_TYPE",
 "message": "<custom_association_type> is not a valid association type between <custom_object_type> and companies",
 "context": {
 "type": [
 "<custom_association_type>"
 ],
 "fromObjectType": [
 "<different_custom_object_type>"
 ],
 "toObjectType": [
 "companies"
 ]
 }
 }
 ],
 "startedAt": "2023-05-12T13:24:37.739Z",
 "completedAt": "2023-05-12T13:24:37.780Z"
}

The error I actually received from the client library:

json: cannot unmarshal string into Go struct field StandardError.errors.category of type hsassoc.ErrorCategory

And that makes sense because according to the OpenAPI spec, StandardError.errors.category is a ErrorCategory, and ErrorCategory is a dictionary containing two keys, but the JSON response from the endpoint returned “VALIDATION_ERROR” for the category, which is not a JSON dictionary.

How to replicate:

1. Generate a golang client library for v3 of the associations API using oapi-codegen based off of HubSpot’s CRM v3 associations OpenAPI spec:

> oapi-codegen -config oapi-codegen-config.yaml -package hsassoc https://api.hubspot.com/api-catalog-public/v1/apis/crm/v3/associations > hsassoc.gen.go

2. Instantiate an association client using that library in a golang program.

	...

	tokenInjector, err := securityprovider.NewSecurityProviderBearerToken(cv.PrivateAppAccessToken)
	if err != nil {
		return nil, mmerrors.Errorf("create token injector: %w", err)
	}

	assocClient, err := hsassoc.NewClientWithResponses(
		hubspotBaseURL,
		hsassoc.WithRequestEditorFn(tokenInjector.Intercept),
	)
	if err != nil {
		return nil, mmerrors.Errorf("instantiate hsassoc client: %w", err)
	}

	...

3. Call the client’s Postcrmv3associationsFromObjectTypeToObjectTypebatchcreateCreateWithResponse method specifying a from and to object type, but with []PublicAssociation items that specify an association type that is not applicable to the supplied from and to object types.

Hello @PCronin9

To replicate the issue, you can use this code.

func parseErrorResponse(response *http.Response) error {
 var errResponse struct {
 Status string `json:"status"`
 NumErrors int `json:"numErrors"`
 Errors []struct {
 Category string `json:"category"`
 SubCategory string `json:"subCategory"`
 Message string `json:"message"`
 Context struct {
 Type []string `json:"type"`
 FromObjectType []string `json:"fromObjectType"`
 ToObjectType []string `json:"toObjectType"`
 } `json:"context"`
 } `json:"errors"`
 }

 if err := json.NewDecoder(response.Body).Decode(&errResponse); err != nil {
 return err
 }

 if errResponse.NumErrors > 0 {
 return errResponse.Errors[0]
 }

 return nil
}

Hi @himanshurauthan, I haven’t tested your solution but I agree the problem could be worked around by modifying the libraries generated and avoiding the methods in the generated libraries that automatically parse the API response. However, given that a spec should match the behavior of the endpoints, the real solution would be for HubSpot to fix their endpoints to match their spec, or to fix the spec to match their endpoints. So my post is trying to be a bug report instead of a call for help. Do you know of a better place to report this bug?