mybatis/mybatis-3 · error · SQLException
SqlRunner could not find a TypeHandler instance for {}
Error message
SqlRunner could not find a TypeHandler instance for {} What it means
SqlRunner.setParameters() throws SQLException when TypeHandlerRegistry has no TypeHandler registered for the concrete class of an argument. SqlRunner resolves handlers purely from args[i].getClass(), so any type outside the built-in set (primitives, dates, strings, enums, etc.) and not user-registered fails here.
Source
Thrown at src/main/java/org/apache/ibatis/jdbc/SqlRunner.java:227
try {
connection.close();
} catch (SQLException e) {
// ignore
}
}
private void setParameters(PreparedStatement ps, Object... args) throws SQLException {
for (int i = 0, n = args.length; i < n; i++) {
if (args[i] == null) {
throw new SQLException(
"SqlRunner requires an instance of Null to represent typed null values for JDBC compatibility");
}
if (args[i] instanceof Null) {
((Null) args[i]).getTypeHandler().setParameter(ps, i + 1, null, ((Null) args[i]).getJdbcType());
} else {
TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(args[i].getClass());
if (typeHandler == null) {
throw new SQLException("SqlRunner could not find a TypeHandler instance for " + args[i].getClass());
} else {
typeHandler.setParameter(ps, i + 1, args[i], null);
}
}
}
}
private List<Map<String, Object>> getResults(ResultSet rs) throws SQLException {
List<Map<String, Object>> list = new ArrayList<>();
List<String> columns = new ArrayList<>();
List<TypeHandler<?>> typeHandlers = new ArrayList<>();
ResultSetMetaData rsmd = rs.getMetaData();
for (int i = 0, n = rsmd.getColumnCount(); i < n; i++) {
columns.add(rsmd.getColumnLabel(i + 1));
try {
Class<?> type = Resources.classForName(rsmd.getColumnClassName(i + 1));
TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(type);
if (typeHandler == null) {View on GitHub (pinned to 008069adb1)
Solutions
- Convert the value to a supported JDBC type before passing it (e.g. uuid.toString(), Year.getValue()).
- Register a handler on the Configuration SqlRunner uses: typeHandlerRegistry.register(MyType.class, new MyTypeHandler()) before constructing SqlRunner.
- Prefer the normal mapper API (which maps types via parameter xmlType/resultSet metadata) for non-standard types instead of SqlRunner.
Example fix
// before
runner.update("insert into t(uuid_col) values (?)", java.util.UUID.randomUUID());
// after
runner.update("insert into t(uuid_col) values (?)", java.util.UUID.randomUUID().toString()); Defensive patterns
Strategy: validation
Validate before calling
// Confirm a handler exists before running
TypeHandler<?> h = configuration.getTypeHandlerRegistry().getTypeHandler(MyType.class);
if (h == null) {
configuration.getTypeHandlerRegistry().register(MyType.class, new MyTypeHandler());
}
SqlRunner runner = new SqlRunner(configuration, conn); Prevention
- Register custom TypeHandlers on the Configuration you hand to SqlRunner before first use.
- Convert exotic types (UUID, Year, custom VOs) to String/long/timestamp at the boundary.
- Keep a project list of supported argument types for SqlRunner in test utilities.
When it happens
Trigger: Passing an exotic argument class to SqlRunner methods: java.util.UUID (older MyBatis versions), java.time Year/Period, a custom value object, or a byte[] subclass, where no handler exists in the registry.
Common situations: Using SqlRunner in tests with java.time or custom types not registered; a TypeHandler registered on a Configuration different from the one SqlRunner was constructed with; version upgrades that change default handler coverage.
Related errors
- SqlRunner requires an instance of Null to represent typed nu
- Could not find type handler for Java type '" + propertyGener
- Could not set parameters for mapping: " + parameterMapping +
- ArrayType Handler requires SQL array or java array parameter
- Error setting non null for parameter #" + i + " with JdbcTyp
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/66f452b677c2874e.
Report an issue: GitHub.