mybatis/mybatis-3 · error · BuilderException

Dynamic content is not allowed when using RAW language

Error message

Dynamic content is not allowed when using RAW language

What it means

RawLanguageDriver forces every statement to be a static, pre-compilable RawSqlSource. After building a SqlSource it checks the concrete class; anything other than RawSqlSource (i.e. DynamicSqlSource) means the script contained dynamic constructs, so a BuilderException is thrown at startup. Dynamic tags (${} substitution, <if>, <where>, <foreach>, etc.) are incompatible with the RAW driver by design.

Source

Thrown at src/main/java/org/apache/ibatis/scripting/defaults/RawLanguageDriver.java:52

  @Override
  public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
    SqlSource source = super.createSqlSource(configuration, script, parameterType);
    checkIsNotDynamic(source);
    return source;
  }

  @Override
  public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType,
      ParamNameResolver paramNameResolver) {
    SqlSource source = super.createSqlSource(configuration, script, parameterType, paramNameResolver);
    checkIsNotDynamic(source);
    return source;
  }

  private void checkIsNotDynamic(SqlSource source) {
    if (!RawSqlSource.class.equals(source.getClass())) {
      throw new BuilderException("Dynamic content is not allowed when using RAW language");
    }
  }

}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Replace dynamic constructs with static SQL: use #{} parameters, split conditional variants into separate statements
  2. Switch those statements back to the default XMLLanguageDriver (remove lang="raw" or per-statement driver override)
  3. If you only need runtime-value binding (not SQL text changes), #{} placeholders are fine under RAW — convert ${} to #{} where possible

Example fix

<!-- before (RawLanguageDriver) -->
<select id="find" lang="raw" ...>SELECT * FROM t WHERE status = #{status}<if test="name != null"> AND name = #{name}</if></select>

<!-- after -->
<select id="find" ...>SELECT * FROM t WHERE status = #{status} AND name = #{name}</select>
Defensive patterns

Strategy: validation

Validate before calling

// at bootstrap, validate each statement against the RAW driver
try {
  rawDriver.createSqlSource(configuration, script, parameterType, paramNameResolver);
} catch (BuilderException e) {
  // statement contains dynamic content; assign it the default XML driver instead
}

Prevention

When it happens

Trigger: Setting defaultLanguageDriverClass (or a statement's lang attribute) to RawLanguageDriver while the mapper still contains ${...}, <if>, <choose>, <foreach>, <set>, <where>, <bind>, or <include> fragments that expand to dynamic SQL.

Common situations: Adopting RawLanguageDriver for startup-time performance/static SQL verification on an existing mapper suite; mixing drivers and forgetting to clean dynamic constructs out of some statements; copy-pasting dynamic SQL into a RAW-driver statement.

Related errors


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