jeecgboot/JeecgBoot · error · ParseException
Unexpected end of string.
Error message
Unexpected end of string.
What it means
After consuming a '/' in the '*' or '/' handling branch, the parser does i++ and then checks i >= s.length(). If the increment was at the very end of the string and there is no character left to read, this is thrown. It differs from 290 in that this is the inner re-check inside the increment block, after the '/' was already accepted as a valid operator at this position.
Source
Thrown at jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java:651
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') {
if(type < DAY_OF_MONTH)View on GitHub (pinned to 96fb33f5ec)
Solutions
- Add the missing integer after the trailing '/'.
- Trim the expression and re-validate field by field to find which field ends in '/'.
- If a step is optional, only append '/step' when the step value is present and > 0.
Example fix
// before - expression ends right after '/' String cron = "0 0 0 * * ? 2025/"; // Unexpected end of string // after - provide the year step String cron = "0 0 0 * * ? 2025/2";
Defensive patterns
Strategy: validation
Validate before calling
// No field may end with '/' (the increment must follow in the same field).
public static String validateNoTrailingSlash(String expr) {
for (String field : expr.trim().split("\\s+")) {
if (field.endsWith("/")) return "field ends with '/' and is missing its increment: " + field;
}
return null;
} Type guard
public static boolean noFieldEndsWithSlash(String expr) {
if (expr == null) return true;
for (String field : expr.trim().split("\\s+")) {
if (field.endsWith("/")) return false;
}
return true;
} Try / catch
try {
new CronExpression(expr);
} catch (ParseException e) {
if (e.getMessage().startsWith("Unexpected end of string")) {
return "The expression is truncated after a '/'; supply the increment. " + e.getMessage();
}
throw e;
} Prevention
- Strip trailing whitespace and ensure no field ends with '/'.
- When concatenating fields programmatically, verify each step value is present.
- Unit-test generated expressions end-to-end before saving them.
When it happens
Trigger: A '*' or value followed by '/' that lands exactly at the end of input with nothing after the i++ advance, e.g. '0 0 0 * * ?/' in a trailing year field, or an expression that ends right after the slash in the field being parsed. Because this is per-field, it fires when the field's substring ends at '/'.
Common situations: Truncated expressions where the final increment digit was chopped off; concatenation that left a '/' at the boundary; year-field appended with an empty step.
Related errors
- '/' must be followed by an integer.
- Increment >= 60 : {incr}
- Increment >= 24 : {incr}
- Increment >= 31 : {incr}
- Increment >= 7 : {incr}
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/9cf27e14e7544ff0.
Report an issue: GitHub.