flowable/flowable-engine · error · FlowableIllegalArgumentException

Converter can only convert instant

Error message

Converter can only convert instant

What it means

InstantRestVariableConverter.convertVariableValue serializes a java.time.Instant to its string form for the REST response. A non-null value that is not an Instant causes this FlowableIllegalArgumentException.

Source

Thrown at modules/flowable-common-rest/src/main/java/org/flowable/common/rest/variable/InstantRestVariableConverter.java:54

    public Object getVariableValue(EngineRestVariable result) {
        if (result.getValue() != null) {
            if (!(result.getValue() instanceof String)) {
                throw new FlowableIllegalArgumentException("Converter can only convert string to instant");
            }
            try {
                return Instant.parse((String) result.getValue());
            } catch (DateTimeParseException e) {
                throw new FlowableIllegalArgumentException("The given variable value is not an instant: '" + result.getValue() + "'", e);
            }
        }
        return null;
    }

    @Override
    public void convertVariableValue(Object variableValue, EngineRestVariable result) {
        if (variableValue != null) {
            if (!(variableValue instanceof Instant)) {
                throw new FlowableIllegalArgumentException("Converter can only convert instant");
            }
            result.setValue(variableValue.toString());
        } else {
            result.setValue(null);
        }
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Convert the value to Instant before conversion (e.g. ((Date) v).toInstant(), or Instant.ofEpochMilli(long)).
  2. Send/write the value as an ISO-8601 instant string and let the engine store an Instant.
  3. Use the 'date' REST type if the underlying object is java.util.Date.
  4. Audit custom variable converter registrations for a collision on the instant type name.

Example fix

// before
converter.convertVariableValue(new Date(), result);
// after
converter.convertVariableValue(new Date().toInstant(), result);
Defensive patterns

Strategy: type-guard

Validate before calling

public static boolean isInstantValue(Object v) { return v == null || v instanceof java.time.Instant; }

Type guard

public static java.time.Instant asInstant(Object v) {
    if (v instanceof java.time.Instant i) return i;
    if (v instanceof java.util.Date d) return d.toInstant();
    if (v instanceof Long m) return java.time.Instant.ofEpochMilli(m);
    return null;
}

Try / catch

try {
    converter.convertVariableValue(value, restVariable);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().equals("Converter can only convert instant")) {
        converter.convertVariableValue(asInstant(value), restVariable);
    } else { throw e; }
}

Prevention

When it happens

Trigger: REST layer hands the instant converter a non-Instant object (String, Date, Long epoch millis) because the value's declared REST type is 'instant' but the deserialized Java object is something else.

Common situations: Clients writing epoch-millis or Date-typed values under the 'instant' type; custom converters misregistered for java.time.Instant; version migration where Date variables are now requested as instant.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/88d63dc7343fc92a. Report an issue: GitHub.