eclipse-vertx/vert.x · error · InputCoercionException

Expected an ISO 8601 formatted date time

Error message

Expected an ISO 8601 formatted date time

What it means

InstantDeserializer parses a JSON string into java.time.Instant and only accepts strings matching the ISO 8601 instant format (e.g. 2024-01-15T10:30:00Z). When the string cannot be parsed by DateTimeFormatter.ISO_INSTANT, it converts the DateTimeException into an InputCoercionException explaining that an ISO 8601 formatted date time was expected. It protects decode targets typed as Instant from silently accepting malformed timestamps.

Source

Thrown at vertx-core/src/main/java21/io/vertx/core/json/jackson/v3/InstantDeserializer.java:35

import java.time.DateTimeException;
import java.time.Instant;

import static java.time.format.DateTimeFormatter.ISO_INSTANT;

class InstantDeserializer extends StdDeserializer<Instant> {

  InstantDeserializer() {
    super(Instant.class);
  }

  @Override
  public Instant deserialize(JsonParser p, DeserializationContext ctxt) {
    String text = p.getString();
    try {
      return Instant.from(ISO_INSTANT.parse(text));
    } catch (DateTimeException e) {
      throw new InputCoercionException(p, "Expected an ISO 8601 formatted date time", p.currentToken(), Instant.class);
    }
  }
}

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Send timestamps in full ISO 8601 instant format, e.g. "2024-01-15T10:30:00Z" or with an explicit offset "2024-01-15T11:30:00+01:00"
  2. Normalize the value before decoding: append "Z" to date-only strings or convert epoch millis programmatically with Instant.ofEpochMilli
  3. If multiple formats must be supported, decode as String and parse with a custom DateTimeFormatter instead of binding directly to Instant

Example fix

// before
String in = "{\"ts\":\"2024-01-15\"}"; // InputCoercionException
Instant ts = Json.decodeValue(in, Wrapper.class).getTs();
// after
String in = "{\"ts\":\"2024-01-15T00:00:00Z\"}";
Instant ts = Json.decodeValue(in, Wrapper.class).getTs();
Defensive patterns

Strategy: validation

Validate before calling

static boolean isIsoInstant(String s) {
  try { java.time.Instant.from(java.time.format.DateTimeFormatter.ISO_INSTANT.parse(s)); return true; }
  catch (java.time.format.DateTimeParseException e) { return false; }
}

Type guard

static java.time.Instant safeParse(String s) {
  try { return java.time.Instant.parse(s); } catch (Exception e) { return null; }
}

Try / catch

try {
  Instant ts = Json.decodeValue(buf, Wrapper.class).getTs();
} catch (InputCoercionException | DecodeException e) {
  log.error("timestamp is not ISO 8601: " + e.getMessage());
}

Prevention

When it happens

Trigger: Decoding JSON into an Instant field or Json.decodeValue target where the JSON string is not strict ISO 8601 instant format: e.g. "2024-01-15" (date only), "2024-01-15T10:30:00" (no offset), "2024-01-15 10:30:00Z" (space separator), epoch millis like "1705309800000", or locale-formatted dates.

Common situations: Frontend sends a date without the trailing Z or offset; legacy systems send timestamps with a space instead of 'T'; APIs send epoch milliseconds as a string; local date/time values produced by JavaScript toISOString-less formatting.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/548d5c5c6ec99bae. Report an issue: GitHub.