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
- Convert the value to Instant before conversion (e.g. ((Date) v).toInstant(), or Instant.ofEpochMilli(long)).
- Send/write the value as an ISO-8601 instant string and let the engine store an Instant.
- Use the 'date' REST type if the underlying object is java.util.Date.
- 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
- Pass java.time.Instant only to the instant converter.
- Convert legacy java.util.Date values with toInstant() first.
- Use the 'date' REST type when the value is a java.util.Date.
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
- Converter can only convert string to instant
- Converter can only convert booleans
- Converter can only convert doubles
- Converter can only convert integers
- Variable '${restVariable.getName()}' has unsupported type: '
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/88d63dc7343fc92a.
Report an issue: GitHub.