Repository navigation
422 with a JSON body that has no validation details throws ValidationException with a blank message #710
Description
Summary
DoclingServeClient.getResponse treats every 422 as a validation error. If the body is a JSON object that has no validation details, it still throws a ValidationException, with an empty ValidationError and a blank error text, and the original response body is not available to the caller.
Reproduction
Tested on main (174a56e) with a WireMock stub for GET /health returning 422 with Content-Type: application/json, on both DoclingServeJackson2Client and DoclingServeJackson3Client (prettyPrint() off):
| Body | Result |
|---|---|
{"error":"gateway says no"} |
ValidationException, message ends with ...request to <url>: followed by nothing |
{} |
same |
{"detail":[]} |
same |
Cause
ValidationError deserialization is lenient: unknown properties are ignored on both Jackson 2 (FAIL_ON_UNKNOWN_PROPERTIES is disabled on the client's mapper) and Jackson 3. Any JSON object therefore deserializes successfully into a ValidationError whose errorDetails list is empty, so no parse failure ever signals "this is not a validation error".
Suggested change
Treat a ValidationError with no details as "not a validation error" and fall back to the generic DoclingServeClientException, which carries the status code and the response body, like any other 4xx/5xx response. In parseValidationError, after the JsonReadException catch that #704 introduces (see below), that is one more step on the Optional:
return Optional.ofNullable(readValue(body, ValidationError.class))
.filter(error -> !error.getErrorDetails().isEmpty());Notes
- This is a behavior change for
{"detail": []}: it would go fromValidationExceptiontoDoclingServeClientException. I have not checked whether docling-serve can ever emit an emptydetaillist; that should be confirmed before deciding. - It touches the same code as fix(client): keep status and body when a 422 body is not JSON #704, which adds a fallback for a
422body that cannot be parsed at all (for example an HTML page from a gateway). I'd suggest landing this after fix(client): keep status and body when a 422 body is not JSON #704, since that PR restructuresparseValidationError, and the filter then becomes a one-line addition. - A regression test needs a JSON body without
detailon both backends, inAbstractDoclingServeClientTests. It only needs plain WireMock bodies, so the normalgetDoclingClient(false, true)client is enough; it does not need the failing-deserializer client. Removing the filter should turn it red on both. - Jackson 2 and Jackson 3 currently disagree on
{"detail":"plain string"}(Jackson 2 gives aValidationException, Jackson 3 aDoclingServeClientException). That is a separate inconsistency, so keep it out of shared assertions.
Related
- fix(client): keep status and body when a 422 body is not JSON #704: fallback for a
422body that is not JSON. It should catchJsonReadException(added by fix(client): log a non-JSON response body as it is #711), notRuntimeException. - logResponse throws on non-JSON response bodies when prettyPrint is enabled, hiding the real error #709, fixed by fix(client): log a non-JSON response body as it is #711:
logResponsethrew on non-JSON bodies whenprettyPrintwas on.readValuenow throws the library-neutralJsonReadExceptionfor text that is not valid JSON or does not match the requested type, on both Jackson backends.
Activity
fix(client): throw DoclingServeClientException for a 422 without vali…
docling-java-ops commentedon Oct 5, 2026
🎉 This issue has been resolved in
v0.7.0(Release Notes)