mybatis/mybatis-3 · error · TypeException
JDBC requires that the JdbcType must be specified for all nu
Error message
JDBC requires that the JdbcType must be specified for all nullable parameters.
What it means
JDBC drivers need a SQL type code to execute PreparedStatement.setNull. When a parameter value is null and MyBatis resolved no JdbcType for it (neither from #{param,jdbcType=...} nor from the environment's jdbcTypeForNull setting), BaseTypeHandler.setParameter throws this TypeException before touching the driver.
Source
Thrown at src/main/java/org/apache/ibatis/type/BaseTypeHandler.java:62
/**
* Sets the configuration.
*
* @param c
* the new configuration
*
* @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This property will remove future.
*/
@Deprecated
public void setConfiguration(Configuration c) {
this.configuration = c;
}
@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
+ "Cause: " + e, e);
}
} else {
try {
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: "
+ e, e);
}
}
}View on GitHub (pinned to 008069adb1)
Solutions
- Declare the type explicitly in the mapper: #{value,jdbcType=VARCHAR} (or the matching SQL type)
- Set a global default in mybatis-config.xml: <setting name="jdbcTypeForNull" value="NULL"/> (or OTHER where the driver accepts it)
- If calling TypeHandler.setParameter directly, always pass a non-null JdbcType for nullable values
Example fix
// before
SELECT * FROM t WHERE name = #{name}
// after
SELECT * FROM t WHERE name = #{name,jdbcType=VARCHAR} Defensive patterns
Strategy: validation
Validate before calling
// before executing: ensure every nullable param has a jdbcType
if (value == null && jdbcType == null) {
throw new IllegalStateException("Parameter '" + name + "' is null and has no jdbcType");
} Try / catch
try { sqlSession.selectOne(...) } catch (TypeException e) { if (e.getMessage().contains("JdbcType must be specified")) { /* add jdbcType to mapper, rethrow otherwise */ } throw e; } Prevention
- Set jdbcTypeForNull globally instead of relying on per-parameter attributes
- Adopt a mapper lint/review rule: every #{param} for a nullable column carries jdbcType
- Cover the null-argument path of each query in tests
When it happens
Trigger: Executing a statement where a nullable parameter is bound as #{value} with no jdbcType attribute while the effective jdbcTypeForNull resolution yields null; or invoking a TypeHandler.setParameter(ps, i, null, null) directly through the API.
Common situations: Optional search filters that are null on some requests; custom DefaultParameterHandler or programmatic SqlSource that drops the jdbcType; migrations between MyBatis versions where configuration defaults differ.
Related errors
- A query was run and no Result Maps were found for the Mapped
- Error setting null for parameter #" + i + " with JdbcType "
- Unknown execution method for: {name}
- Invalid bound statement (not found): {mapperInterface}.{meth
- Type {type} is not known to the MapperRegistry.
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/c7c8e1ee2b3287f2.
Report an issue: GitHub.