hs-web/hsweb-framework · error · DecodingException

JSON decoding error

Error message

JSON decoding error: ${originalMessage}

What it means

Jackson2Tokenizer.tokenize() wraps Jackson's JsonProcessingException into Spring's DecodingException with the original parser message, signalling malformed JSON input while streaming-decoding a byte Flux.

Solutions

  1. Validate/fix the JSON payload sent by the client
  2. Ensure Content-Type is application/json and encoding is UTF-8
  3. Log the full DecodingException cause for the exact parse position
  4. Test the payload with a strict JSON parser to locate the syntax error

Example fix

// before
curl -X POST -d 'name=abc' /api/items
// after
curl -X POST -H 'Content-Type: application/json' -d '{"name":"abc"}' /api/items
Defensive patterns

Strategy: try-catch

Validate before calling

try (JsonParser p = new JsonFactory().createParser(bytes)) { while (p.nextToken() != null) {} } catch (JsonProcessingException e) { /* invalid */ }

Type guard

static boolean isValidJson(byte[] bytes) {
    try { new JsonFactory().createParser(bytes).readValueAsTree(); return true; }
    catch (Exception e) { return false; }
}

Try / catch

try {
    return tokenizer.tokenize(buffer);
} catch (DecodingException e) {
    log.warn("malformed JSON: {}", e.getOriginalMessage());
    return Mono.error(ResponseStatusException(HttpStatus.BAD_REQUEST, "Malformed JSON", e));
}

Prevention

When it happens

Trigger: Feeding invalid JSON bytes (syntax errors, truncated stream, wrong encoding) into the tokenizer's input feeder; parseTokenBufferFlux encounters a token Jackson cannot parse.

Common situations: Client sends malformed request bodies to reactive endpoints expecting JSON; truncated upload; charset mismatch (UTF-8 BOM or invalid bytes); sending form-encoded data to a JSON decoder.

Related errors


AI-assisted analysis of hs-web/hsweb-framework@b2cfc85a57 (2026-09-13). Data as JSON: /api/errors/81668785318309bd. Report an issue: GitHub.

Appendix: source

Thrown at hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/Jackson2Tokenizer.java:89

		this.parser = parser;
		this.deserializationContext = deserializationContext;
		this.tokenizeArrayElements = tokenizeArrayElements;
		this.tokenBuffer = new TokenBuffer(parser, deserializationContext);
		this.inputFeeder = (ByteArrayFeeder) this.parser.getNonBlockingInputFeeder();
	}


	private List<TokenBuffer> tokenize(DataBuffer dataBuffer) {
		byte[] bytes = new byte[dataBuffer.readableByteCount()];
		dataBuffer.read(bytes);
		DataBufferUtils.release(dataBuffer);

		try {
			this.inputFeeder.feedInput(bytes, 0, bytes.length);
			return parseTokenBufferFlux();
		}
		catch (JsonProcessingException ex) {
			throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
		}
		catch (IOException ex) {
			throw Exceptions.propagate(ex);
		}
	}

	private Flux<TokenBuffer> endOfInput() {
		return Flux.defer(() -> {
			this.inputFeeder.endOfInput();
			try {
				return Flux.fromIterable(parseTokenBufferFlux());
			}
			catch (JsonProcessingException ex) {
				throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
			}
			catch (IOException ex) {
				throw Exceptions.propagate(ex);
			}

View on GitHub (pinned to b2cfc85a57)