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
- 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
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
- 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
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
- No task information found for task with id: [%s]
- Cannot find any supervisor with id: [%s]
- Cannot find any task with id: [%s]
- Unable to parse row [%s]
- Invalid JSON inside unknown key:
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/e7e566dabf172ffc.
Report an issue: GitHub.