eclipse-vertx/vert.x · error · DecodeException
Failed to decode:${e.getMessage()}
Error message
Failed to decode:${e.getMessage()} What it means
DatabindCodec.fromStream wraps any IOException raised while creating or reading a Jackson JsonParser from an InputStream into a DecodeException 'Failed to decode:...'. It signals the input stream did not yield parseable JSON.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/json/jackson/DatabindCodec.java:103
}
@Override
public <T> T fromBuffer(Buffer buf, Class<T> clazz) throws DecodeException {
return fromParser(createParser(buf), clazz);
}
public <T> T fromBuffer(Buffer buf, TypeReference<T> typeRef) throws DecodeException {
return fromParser(createParser(buf), typeRef);
}
@Override
public <T> T fromStream(InputStream in, Class<T> clazz) throws DecodeException {
try {
JsonParser parser = mapper.getFactory().createParser(in);
parser.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
return fromParser(parser, clazz);
} catch (IOException e) {
throw new DecodeException("Failed to decode:" + e.getMessage(), e);
}
}
public static JsonParser createParser(BufferInternal buf) {
try {
return DatabindCodec.mapper.getFactory().createParser((InputStream) new ByteBufInputStream(buf.getByteBuf()));
} catch (IOException e) {
throw new DecodeException("Failed to decode:" + e.getMessage(), e);
}
}
public static JsonParser createParser(String str) {
try {
return DatabindCodec.mapper.getFactory().createParser(str);
} catch (IOException e) {
throw new DecodeException("Failed to decode:" + e.getMessage(), e);
}
}View on GitHub (pinned to fb308bd8c3)
Solutions
- Check getCause() for the underlying IOException message (it names the real problem).
- Verify the stream is open and positioned at the start (re-open the resource rather than reusing a consumed stream).
- Validate the JSON is well-formed (e.g. dump the bytes first: IOUtils.toString).
- Ensure the stream charset is UTF-8 or another JSON-compatible encoding.
Example fix
// before
InputStream in = socket.getInputStream();
Json.decodeValue(in, Config.class); // DecodeException on truncated data
// after
String text = in.readAllBytes() ... validate;
if (!text.trim().isEmpty()) {
Config c = Json.decodeValue(Buffer.buffer(text), Config.class);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (in == null) throw new IllegalArgumentException("input stream is null");
if (in.available() == 0 && expectsData) throw new IllegalStateException("input stream is empty"); Type guard
static boolean hasReadableData(InputStream in) throws IOException {
return in != null && in.read() != -1; // mark/reset to rewind if supported
} Try / catch
try (InputStream in = openStream()) {
return Json.decodeValue(in, Config.class);
} catch (DecodeException e) {
throw new ConfigException("Cannot parse config: " + e.getCause().getMessage(), e);
} Prevention
- Use try-with-resources so streams are fresh, open, and closed once.
- Never re-consume an exhausted stream; re-open the resource instead.
- Prefer decoding from String/Buffer so you can log the exact payload on failure.
When it happens
Trigger: Json.decodeValue(InputStream) / DatabindCodec.fromStream(clazz) with an empty stream, already-closed stream, malformed JSON, an invalid charset, or an IO error mid-read (network drop, premature EOF).
Common situations: Reading a config resource that does not exist on the classpath (stream is empty/null content); passing a response body stream that was already consumed; feeding truncated JSON from a socket.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid JSON array: ${json}
- Invalid JSON array: ${buf}
- Invalid JSON object: ${json}
- Invalid JSON object: ${buf}
- Unexpected trailing token
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/e9e680ebc9716ec6.
Report an issue: GitHub.