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

  1. Declare the type explicitly in the mapper: #{value,jdbcType=VARCHAR} (or the matching SQL type)
  2. Set a global default in mybatis-config.xml: <setting name="jdbcTypeForNull" value="NULL"/> (or OTHER where the driver accepts it)
  3. 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

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


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/c7c8e1ee2b3287f2. Report an issue: GitHub.