kestra-io/kestra · error · PebbleException
'number' filter can only be applied to String. Actual type w
Error message
'number' filter can only be applied to String. Actual type was: {} What it means
Thrown by the 'number' Pebble filter when the input is not a String. The filter delegates to Apache Commons `NumberUtils.createXxx` which only accepts String inputs, so any other type is rejected up front with the actual class name in the message.
Source
Thrown at core/src/main/java/io/kestra/core/runners/pebble/filters/NumberFilter.java:26
import io.pebbletemplates.pebble.error.PebbleException;
import io.pebbletemplates.pebble.extension.Filter;
import io.pebbletemplates.pebble.template.EvaluationContext;
import io.pebbletemplates.pebble.template.PebbleTemplate;
public class NumberFilter implements Filter {
@Override
public List<String> getArgumentNames() {
return List.of("type");
}
@Override
public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) throws PebbleException {
if (input == null) {
return null;
}
if (!(input instanceof String)) {
throw new PebbleException(null, "'number' filter can only be applied to String. Actual type was: " + input.getClass().getName(), lineNumber, self.getName());
}
String type = (String) args.getOrDefault("type", "");
String val = (String) input;
switch (type) {
case "INT":
return NumberUtils.createInteger(val);
case "FLOAT":
return NumberUtils.createFloat(val);
case "LONG":
return NumberUtils.createLong(val);
case "DOUBLE":
return NumberUtils.createDouble(val);
case "BIGDECIMAL":
return NumberUtils.createBigDecimal(val);
case "BIGINTEGER":
return NumberUtils.createBigInteger(val);View on GitHub (pinned to 823fada927)
Solutions
- Drop the `| number` filter if the value is already numeric.
- Stringify first if you really need to re-parse: `{{ myval | toString | number(type="INT") }}`.
- Check the upstream task output type declaration and align the filter chain.
Example fix
# before
{{ outputs.fetch.value | number(type="INT") }}
# after - value is already an integer
{{ outputs.fetch.value }} Defensive patterns
Strategy: type-guard
Validate before calling
# Only stringify-and-parse when the value is not already numeric:
{% if myval is number %}
{{ myval }}
{% else %}
{{ myval | toString | number(type="INT") }}
{% endif %} Type guard
# Pebble: `is number` narrows numeric types away from the string-only filter.
Prevention
- Check the upstream output type before applying `| number`.
- Avoid redundant conversions; if the value is already numeric, drop the filter.
- Use `toString` explicitly when you must re-parse a non-string.
When it happens
Trigger: Calling `{{ someInt | number }}` where `someInt` is already a numeric type (Integer, Long, Double); passing a Boolean; passing a parsed JSON number that Jackson already converted to a numeric type.
Common situations: Double conversion: a value is already numeric but the flow assumes it is a string; consuming a task output whose declared type is `INTEGER` and then applying `| number` redundantly.
Related errors
- Need a string to hash
- 'keys' filter can only be applied to List, Map, Array. Actua
- The argument ''{0}'' is required.
- Unknown value element type: {}
- Cannot concat {} with {}
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/bf91a2dc9870afb3.
Report an issue: GitHub.