mybatis/mybatis-3 · error · RuntimeSqlException
Line missing end-of-line terminator ({}) => {}
Error message
Line missing end-of-line terminator ({}) => {} What it means
ScriptRunner throws RuntimeSqlException from checkForMissingLineTerminator() when, after consuming the whole script, leftover non-whitespace text remains in the command buffer. This means the final SQL command was never terminated with the configured delimiter (default ';'), so it was never executed. The offending partial command text is included in the message.
Source
Thrown at src/main/java/org/apache/ibatis/jdbc/ScriptRunner.java:209
}
} catch (Throwable t) {
throw new RuntimeSqlException("Could not commit transaction. Cause: " + t, t);
}
}
private void rollbackConnection() {
try {
if (!connection.getAutoCommit()) {
connection.rollback();
}
} catch (Throwable t) {
// ignore
}
}
private void checkForMissingLineTerminator(StringBuilder command) {
if (command != null && command.toString().trim().length() > 0) {
throw new RuntimeSqlException("Line missing end-of-line terminator (" + delimiter + ") => " + command);
}
}
private void handleLine(StringBuilder command, String line) throws SQLException {
String trimmedLine = line.trim();
if (lineIsComment(trimmedLine)) {
Matcher matcher = DELIMITER_PATTERN.matcher(trimmedLine);
if (matcher.find()) {
delimiter = matcher.group(5);
}
println(trimmedLine);
} else if (commandReadyToExecute(trimmedLine)) {
command.append(line, 0, line.lastIndexOf(delimiter));
command.append(LINE_SEPARATOR);
println(command);
executeStatement(command.toString());
command.setLength(0);
} else if (trimmedLine.length() > 0) {View on GitHub (pinned to 008069adb1)
Solutions
- Add the delimiter (';' by default) at the end of the last statement in the script.
- If the script uses a different terminator, ensure the final statement ends with that exact delimiter string.
- If you deliberately want the whole script sent at once, call runner.setSendFullScript(true) so line-by-line delimiter parsing is bypassed.
Example fix
-- before (end of script.sql) INSERT INTO users(id, name) VALUES (3, 'carl') -- after INSERT INTO users(id, name) VALUES (3, 'carl');
Defensive patterns
Strategy: validation
Validate before calling
// Before running, check the last non-whitespace chars of the script end with the delimiter
String sql = Files.readString(path);
String trimmed = sql.trim();
String delim = ";"; // match ScriptRunner delimiter
if (!trimmed.endsWith(delim)) {
throw new IllegalArgumentException("Script must end with '" + delim + "': " + path);
} Try / catch
try {
runner.runScript(reader);
} catch (RuntimeSqlException e) {
if (e.getMessage() != null && e.getMessage().contains("missing end-of-line terminator")) {
// append delimiter and retry once with corrected script
}
throw e;
} Prevention
- Add a lint step in CI that rejects .sql files not ending with the statement delimiter.
- Keep delimiter usage consistent when using DELIMITER directives for procedures.
- Consider setSendFullScript(true) for single-statement-test scripts where delimiter parsing is unnecessary.
When it happens
Trigger: A .sql script whose last statement lacks a trailing ';' (e.g. ends with the last line of an INSERT with no terminator), or a custom delimiter (setDelimiter) that does not match what the script uses on its final statement; also sendFullScript=false with a last line that has no delimiter.
Common situations: Hand-edited migration files where the final semicolon was accidentally deleted; scripts generated by tools that omit the last terminator; changing the delimiter for stored procedures (DELIMITER $$) but forgetting the final $$.
Related errors
- Could not commit transaction. Cause: {}
- Constructor auto-mapping of ''{0}'' failed. The constructor
- Statement returned {} results where exactly one (1) was expe
- Error evaluating XPath. Cause: {}
- Error creating document instance. Cause: {}
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/c7ea44792c6e2d9b.
Report an issue: GitHub.