{"record":{"id":"e7e566dabf172ffc","repo":"apache/druid","slug":"unknown-json-mapping-exception","errorCode":null,"errorMessage":"unknown json mapping exception","messagePattern":"unknown json mapping exception","errorType":"http","errorClass":"JsonMappingException","httpStatus":400,"severity":"info","filePath":"server/src/main/java/org/apache/druid/server/initialization/jetty/CustomExceptionMapper.java","lineNumber":42,"sourceCode":"import com.google.common.collect.ImmutableMap;\nimport org.apache.druid.java.util.common.logger.Logger;\n\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\nimport javax.ws.rs.ext.Provider;\n\n@Provider\npublic class CustomExceptionMapper implements ExceptionMapper<JsonMappingException>\n{\n  private static final Logger log = new Logger(CustomExceptionMapper.class);\n  public static final String ERROR_KEY = \"error\";\n  public static final String UNABLE_TO_PROCESS_ERROR = \"unknown json mapping exception\";\n\n  @Override\n  public Response toResponse(JsonMappingException exception)\n  {\n    log.warn(exception.getMessage() == null ? UNABLE_TO_PROCESS_ERROR : exception.getMessage());\n    return Response.status(Response.Status.BAD_REQUEST)\n                   .entity(ImmutableMap.of(\n                       ERROR_KEY,\n                       exception.getMessage() == null\n                       ? UNABLE_TO_PROCESS_ERROR\n                       : exception.getMessage().split(System.lineSeparator())[0]\n                   ))\n                   .type(MediaType.APPLICATION_JSON)\n                   .build();\n  }\n}\n","sourceCodeStart":24,"sourceCodeEnd":54,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/server/initialization/jetty/CustomExceptionMapper.java#L24-L54","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the 'error' field of the 400 response — it contains the Jackson message's first line naming the offending field/type","Validate the JSON payload against the endpoint's expected schema and fix field names/types","Ensure the client and server Druid versions agree on request object schemas"],"exampleFix":"// before\n{\"maxRows\": \"1000\"}   // string where int expected\n// after\n{\"maxRows\": 1000}","handlingStrategy":"try-catch","validationCode":"new ObjectMapper().readTree(json); // fail fast client-side before posting; optionally validate types against the request schema","typeGuard":"boolean isJsonObject(String body) { try { return new ObjectMapper().readTree(body).isObject(); } catch (Exception e) { return false; } }","tryCatchPattern":"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]); }","preventionTips":["Serialize request bodies from typed clients instead of hand-written JSON strings","Pin client and server to compatible Druid versions","Check the returned 'error' field's first line — Jackson names the bad field there"],"tags":["http","json","jackson","rest-api"],"backgroundTag":"json-parse-error","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}