Skip to content

[Cosmos] Fix ClassCastException when building CosmosException from an empty error response body #49322

@marcellustavares

Description

@marcellustavares

Describe the bug
JsonSerializable.fromJson(String, ObjectMapper) performs an unchecked cast of the parsed tree to ObjectNode:

return (ObjectNode) objectMapper.readTree(json);

When json is empty or blank, ObjectMapper.readTree(...) returns a MissingNode (not an ObjectNode), so the cast throws ClassCastException: class ...MissingNode cannot be cast to class ...ObjectNode.

This is reached on the error-handling path: when a request gets an error HTTP response with an empty body, HttpClientUtils.createDocumentClientException builds the exception from the body, defaulting an empty body to StringUtils.EMPTY and then calling new CosmosError(body):

Exception or Stack Trace
Observed in production on azure-cosmos:4.80.0 (manifests as a CosmosException with statusCode 0):

Caused by: java.lang.ClassCastException: class com.fasterxml.jackson.databind.node.MissingNode cannot be cast to class com.fasterxml.jackson.databind.node.ObjectNode
	at com.azure.cosmos.implementation.JsonSerializable.fromJson(JsonSerializable.java:618)
	at com.azure.cosmos.implementation.JsonSerializable.<init>(JsonSerializable.java:93)
	at com.azure.cosmos.implementation.CosmosError.<init>(CosmosError.java:35)
	at com.azure.cosmos.implementation.directconnectivity.HttpClientUtils.lambda$createDocumentClientException$2(HttpClientUtils.java:45)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:106)
	... 58 more

The enclosing CosmosException is created here, carrying statusCode 0 and an empty responseHeaders {}:

 at com.azure.cosmos.BridgeInternal.createCosmosException(BridgeInternal.java:416)
    at com.azure.cosmos.implementation.directconnectivity.GatewayAddressCache.lambda$getServerAddressesViaGatewayInternalAsync$11(GatewayAddressCache.java:514)

To Reproduce
The crash happens inside the SDK's own exception construction, so it can be reproduced deterministically by exercising the exact call the SDK makes for an empty error body — new CosmosError(<empty/blank string>):

  1. Add com.azure:azure-cosmos:4.80.0 to the classpath.
  2. Construct a CosmosError from an empty (or whitespace-only) body, as HttpClientUtils.createDocumentClientException does when an error response has no body.
  3. Observe ClassCastException instead of a usable CosmosError.

(In a live service this occurs when a Gateway/server error response is returned with an empty body — e.g. transient connectivity errors during address resolution.)

Code Snippet
Minimal reproduction (throws on 4.80.0):

import com.azure.cosmos.implementation.CosmosError;

// Both throw: java.lang.ClassCastException: MissingNode cannot be cast to ObjectNode
new CosmosError("");
new CosmosError("   ");

// Control: a valid JSON object works fine
new CosmosError("{}"); // OK

Proposed regression test (TestNG, unit group), alongside the existing JsonSerializableTest:

@Test(groups = {"unit"})
public void instantiateFromEmptyJsonStringDoesNotThrow() {
    // An error HTTP response with an empty/blank body becomes a CosmosError via
    // HttpClientUtils.createDocumentClientException -> new CosmosError(body).
    for (String emptyBody : Arrays.asList("", "   ")) {
        CosmosError error = new CosmosError(emptyBody);
        assertThat(error).isNotNull();
        assertThat(error.getCode()).isNull();
        assertThat(error.getMessage()).isNull();
    }
}

Expected behavior
Constructing a CosmosError/JsonSerializable from an empty or blank body should not throw ClassCastException. An empty body should yield an empty error object.

Screenshots
N/A

Setup (please complete the following information):
N/A

Additional context
N/a

Information Checklist

  • Bug Description Added
  • Repro Steps Added
  • Setup information Added

Metadata

Metadata

Assignees

No one assigned

    Labels

    ClientThis issue points to a problem in the data-plane of the library.CosmosService AttentionWorkflow: This issue is responsible by Azure service team.customer-reportedIssues that are reported by GitHub users external to the Azure organization.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions