apache/druid · info · JsonMappingException

unknown json mapping exception

Error message

unknown json mapping exception

What it means

CustomExceptionMapper maps Jackson JsonMappingException from JAX-RS endpoints to HTTP 400 with an 'error' payload. When the exception message is null it substitutes this static string; otherwise it logs the message and returns its first line. It indicates the request body's JSON could not be mapped to the expected request object.

Source

Thrown at server/src/main/java/org/apache/druid/server/initialization/jetty/CustomExceptionMapper.java:42

import com.google.common.collect.ImmutableMap;
import org.apache.druid.java.util.common.logger.Logger;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class CustomExceptionMapper implements ExceptionMapper<JsonMappingException>
{
  private static final Logger log = new Logger(CustomExceptionMapper.class);
  public static final String ERROR_KEY = "error";
  public static final String UNABLE_TO_PROCESS_ERROR = "unknown json mapping exception";

  @Override
  public Response toResponse(JsonMappingException exception)
  {
    log.warn(exception.getMessage() == null ? UNABLE_TO_PROCESS_ERROR : exception.getMessage());
    return Response.status(Response.Status.BAD_REQUEST)
                   .entity(ImmutableMap.of(
                       ERROR_KEY,
                       exception.getMessage() == null
                       ? UNABLE_TO_PROCESS_ERROR
                       : exception.getMessage().split(System.lineSeparator())[0]
                   ))
                   .type(MediaType.APPLICATION_JSON)
                   .build();
  }
}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Read the 'error' field of the 400 response — it contains the Jackson message's first line naming the offending field/type
  2. Validate the JSON payload against the endpoint's expected schema and fix field names/types
  3. Ensure the client and server Druid versions agree on request object schemas

Example fix

// before
{"maxRows": "1000"}   // string where int expected
// after
{"maxRows": 1000}
Defensive patterns

Strategy: try-catch

Validate before calling

new ObjectMapper().readTree(json); // fail fast client-side before posting; optionally validate types against the request schema

Type guard

boolean isJsonObject(String body) { try { return new ObjectMapper().readTree(body).isObject(); } catch (Exception e) { return false; } }

Try / catch

try { postJson(endpoint, payload); } catch (BadRequestException e) { String err = e.getResponse().readEntity(Map.class).get("error").toString(); LOG.error("Server rejected JSON: {}", err.split(System.lineSeparator())[0]); }

Prevention

When it happens

Trigger: Any Druid HTTP endpoint receiving a JSON body that Jackson cannot map — wrong field types (e.g. string where number expected), unknown structure, malformed nested objects, or a body that fails during deserialization in a resource method.

Common situations: Automation posting hand-written JSON to task/query/config endpoints; schema drift between client and server versions; JSON that is syntactically valid but type-incompatible with the target POJO.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/e7e566dabf172ffc. Report an issue: GitHub.