flowable/flowable-engine · error · ParseException
Unexpected end of string.
Error message
Unexpected end of string.
What it means
Thrown when a '/' increment marker is found and the parser advances past it (i++) but there are no characters left: i >= s.length(). Same intent as the previous check but covers the exact end-of-string case where '/' is the last character of the entire expression.
Solutions
- Complete the increment: '/5' instead of trailing '/'.
- Check the storage/config layer for silent truncation (column size, .properties line handling, trim logic).
- Log the raw expression length and content when ParseException occurs to spot truncation.
- Add a startup validation pass over all configured cron expressions.
Example fix
// before
new CronExpression("0 0 12 * */");
// after
new CronExpression("0 0 12 * */2"); Defensive patterns
Strategy: validation
Validate before calling
String trimmed = expr.trim();
if (trimmed.endsWith("/")) {
throw new IllegalArgumentException("Cron expression ends with '/': " + expr);
} Try / catch
try {
new CronExpression(expr);
} catch (java.text.ParseException e) {
if (e.getMessage().contains("Unexpected end of string")) {
log.error("Cron truncated (len={}): '{}'", expr.length(), expr);
}
} Prevention
- Beware column-length/property truncation silently cutting expressions
- Log expression length on parse failure to detect truncation
- Keep the raw expression immutable once validated
When it happens
Trigger: new CronExpression("0 0 12 * */") — expression ends immediately after '/'; truncation in property files, database columns with limited length, or log/console copy-paste cutting the tail.
Common situations: VARCHAR/property length truncation silently cutting the cron string; copy-paste missing the final token; string-splitting code that drops the last field's step.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- A numeric value between 1 and 5 must follow the '#' option
- '?' can only be specified for Day-of-Month -OR- Day-of-Week.
- '?' can only be specified for Day-of-Month or Day-of-Week.
- Illegal character after ?:
- Illegal characters for this position: '
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/1b2fd7a3e69c3357.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java:644
addToSet(NO_SPEC_INT, -1, 0, type);
return i;
}
if (c == '*' || c == '/') {
if (c == '*' && (i + 1) >= s.length()) {
addToSet(ALL_SPEC_INT, -1, incr, type);
return i + 1;
} else if (c == '/' && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t')) {
throw new ParseException("'/' must be followed by an integer.", i);
} else if (c == '*') {
i++;
}
c = s.charAt(i);
if (c == '/') { // is an increment specified?
i++;
if (i >= s.length()) {
throw new ParseException("Unexpected end of string.", i);
}
incr = getNumericValue(s, i);
i++;
if (incr > 10) {
i++;
}
checkIncrementRange(incr, type, i);
} else {
incr = 1;
}
addToSet(ALL_SPEC_INT, -1, incr, type);
return i;
} else if (c == 'L') {
i++;
if (type == DAY_OF_MONTH) {View on GitHub (pinned to d6d39ce1c6)