Skip to content

StreamConstraintsException not caught in ServerJacksonMessageBodyReader - results in 500 instead of 400 #52693

@pschaub

Description

@pschaub

Describe the bug

When a JSON request body contains a number exceeding Jackson's default maximum number length of 1000 digits, the server responds with HTTP 500 Internal Server Error instead of 400 Bad Request.

ServerJacksonMessageBodyReader.readFrom() and FullyFeaturedServerJacksonMessageBodyReader.readFrom() catch StreamReadException | DatabindException, but not StreamConstraintsException.

ServerJacksonMessageBodyReader.java L59-L67:

} catch (StreamReadException | DatabindException e) {
    /*
     * As JSON is evaluated, it can be invalid due to one of two reasons:
     * 1) Malformed JSON. Un-parsable JSON results in a StreamReadException
     * 2) Valid JSON that violates some binding constraint, ...
     * Violations of these types are captured via a DatabindException.
     */
    throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
}

Same in FullyFeaturedServerJacksonMessageBodyReader.java L81-L89.

Important

StreamConstraintsException extends JsonProcessingException directly — not StreamReadException. This means it is not covered by the existing catch blocks.

JsonProcessingException
├── StreamReadException              ← caught by readFrom() → wrapped as 400
│   └── InputCoercionException
├── DatabindException                ← caught by readFrom() → wrapped as 400
│   └── MismatchedInputException     ← rethrown → BuiltinMismatchedInputExceptionMapper → 400
└── StreamConstraintsException       ← NOT caught → propagates as IOException → 500

The exception is thrown by Jackson's StreamReadConstraints.validateIntegerLength() (and validateFPLength()) when the digit count exceeds DEFAULT_MAX_NUM_LEN = 1000:

public void validateIntegerLength(int length) throws StreamConstraintsException {
    if (length > _maxNumLen) {
        throw _constructException(
                "Number value length (%d) exceeds the maximum allowed (%d, from %s)",
                length, _maxNumLen, _constrainRef("getMaxNumberLength"));
    }
}

The check is strictly greater than (length > _maxNumLen), so 1000 digits pass but 1001 digits trigger the exception.

Affected Quarkus versions

StreamConstraintsException and StreamReadConstraints (including DEFAULT_MAX_NUM_LEN = 1000) were both introduced in Jackson 2.15.0 (@since 2.15). The exception does not exist in Jackson 2.14.

Quarkus Jackson Affected?
3.0.0.Final 2.14.2 No
3.1.0.Final 2.15.0 Yes — first affected
3.27.0 2.19.2 Yes
3.27.2 2.19.2 Yes
main (as of 2026-02-20) 2.21.0 Yes

A search for StreamConstraintsException in the Quarkus codebase at main returns zero results — it is not handled anywhere.

Expected behavior

HTTP 400 Bad Request - consistent with how all other Jackson parsing errors (StreamReadException, DatabindException, MismatchedInputException) are handled by the same readFrom() method.

Actual behavior

HTTP 500 Internal Server Error.

How to Reproduce?

Minimal endpoint:

@Path("test")
public class TestEndpoint {
    public static class Dto {
        public Integer value;
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Dto put(Dto dto) {
        return dto;
    }
}
# 1000 digits → 400 (passes constraint, fails on type conversion → InputCoercionException → caught)
curl -s -o /dev/null -w "%{http_code}" -X PUT http://localhost:8080/test \
  -H 'Content-Type: application/json' \
  -d "{\"value\": $(printf '9%.0s' $(seq 1 1000))}"

# 1001 digits → 500 (exceeds constraint → StreamConstraintsException → NOT caught)
curl -s -o /dev/null -w "%{http_code}" -X PUT http://localhost:8080/test \
  -H 'Content-Type: application/json' \
  -d "{\"value\": $(printf '9%.0s' $(seq 1 1001))}"

Note

The boundary is exactly 1001 digits. Jackson's check is length > 1000 (strictly greater than), so 1000 digits pass the constraint and fail later on type conversion (InputCoercionException, which is caught). 1001 digits trigger StreamConstraintsException before any type conversion happens.

Output of uname -a or ver

Linux 5.15.0-168-generic #178-Ubuntu SMP Fri Jan 9 19:05:03 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

OpenJDK Runtime Environment (build 21.0.10+7-Ubuntu-122.04)

Quarkus version or git rev

Verified on 3.27.2 and main (as of 2026-02-20, identical catch blocks).

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.12

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/jacksonIssues related to Jackson (JSON library)area/restkind/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions