flowable/flowable-engine · error · ScanException
unterminated string
Error message
unterminated string
What it means
Scanner.nextString() throws ScanException('unterminated string') when a string literal ends with a lone backslash: the input ends immediately after an escape character, so the closing quote is never reached. The 'expected' field indicates the closing quote or another escape character was needed.
Solutions
- Ensure the string literal has a closing quote and does not end with a dangling backslash.
- Double the backslash ('\\') when a literal backslash is intended before the end of the string.
- Log the ScanException position to find the exact spot in the expression.
Example fix
// before
String expr = "${'C:\\path\\'"; // ends with lone backslash
// after
String expr = "${'C:\\path\\user'}"; Defensive patterns
Strategy: validation
Validate before calling
boolean endsWithDanglingBackslash(String expr) { return expr.endsWith("\\"); }
// reject before building Try / catch
try {
builder.build(expr);
} catch (TreeBuilderException e) {
if ("unterminated string".equals(e.getMessage())) {
throw new IllegalArgumentException("Dangling backslash or missing quote in: " + expr);
}
throw e;
} Prevention
- Never end a string literal with a single backslash; double it for a literal backslash.
- Use forward slashes or File/Path APIs for paths instead of backslash literals.
- Escape via the source language's rules before the string reaches EL.
- Lint expressions for trailing backslashes in config.
When it happens
Trigger: An EL string literal where the input terminates right after a backslash, e.g. "${'abc\\'" (backslash is the last character of the input), encountered while scanning inside a quoted string.
Common situations: Expressions generated by templates or shell scripts where trailing backslashes escape quotes incorrectly; Windows-style paths written as '${'C:\\users\\' }' with an odd number of backslashes; manual edits that dropped the closing quote.
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
- invalid escape sequence \\
- invalid character '" + c1 + "'
- Builder is missing constructor (can't pass features)
- Cannot change fixed value with
- Cannot coerce property to array index:
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/1ca8238397a0e1c6.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/Scanner.java:311
if (escaped) {
builder.append('\\');
}
return token(Symbol.TEXT, builder.toString(), i - position);
}
/**
* string token
*/
protected Token nextString() throws ScanException {
builder.setLength(0);
char quote = input.charAt(position);
int i = position+1;
int l = input.length();
while (i < l) {
char c = input.charAt(i++);
if (c == '\\') {
if (i == l) {
throw new ScanException(position, "unterminated string", quote + " or \\");
} else {
c = input.charAt(i++);
if (c == '\\' || c == '\'' || c == '\"') {
builder.append(c);
} else {
throw new ScanException(position, "invalid escape sequence \\" + c, "\\', \\\" or \\\\");
}
}
} else if (c == quote) {
return token(Symbol.STRING, builder.toString(), i - position);
} else {
builder.append(c);
}
}
throw new ScanException(position, "unterminated string", String.valueOf(quote));
}
/**View on GitHub (pinned to d6d39ce1c6)