mybatis/mybatis-3 · error · IncompleteElementException

Cache-ref not yet resolved

Error message

Cache-ref not yet resolved

What it means

Thrown by addMappedStatement() when the flag unresolvedCacheRef is still true: this mapper's <cache-ref> could not be resolved yet, so statements must not be cached with a null/stale cache. It is an IncompleteElementException, so the whole mapped statement is deferred and rebuilt on a later parse pass once the referenced cache exists.

Source

Thrown at src/main/java/org/apache/ibatis/builder/MapperBuilderAssistant.java:208

    ResultMapping resultMapping = buildResultMapping(resultType, null, column, javaType, jdbcType, null, null, null,
        null, typeHandler, new ArrayList<>(), null, null, false);
    Map<String, String> namespaceDiscriminatorMap = new HashMap<>();
    for (Map.Entry<String, String> e : discriminatorMap.entrySet()) {
      String resultMap = e.getValue();
      resultMap = applyCurrentNamespace(resultMap, true);
      namespaceDiscriminatorMap.put(e.getKey(), resultMap);
    }
    return new Discriminator.Builder(configuration, resultMapping, namespaceDiscriminatorMap).build();
  }

  public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType,
      SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, Class<?> parameterType,
      String resultMap, Class<?> resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache,
      boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId,
      LanguageDriver lang, String resultSets, boolean dirtySelect, ParamNameResolver paramNameResolver) {

    if (unresolvedCacheRef) {
      throw new IncompleteElementException("Cache-ref not yet resolved");
    }

    id = applyCurrentNamespace(id, false);

    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
        .resource(resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType)
        .keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang)
        .resultOrdered(resultOrdered).resultSets(resultSets)
        .resultMaps(getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType)
        .flushCacheRequired(flushCache).useCache(useCache).cache(currentCache).dirtySelect(dirtySelect)
        .paramNameResolver(paramNameResolver);

    ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }

    MappedStatement statement = statementBuilder.build();

View on GitHub (pinned to 008069adb1)

Solutions

  1. Fix the underlying cache-ref: make sure the referenced namespace exists and declares a cache (see errors 22/23)
  2. Check that the referenced mapper file is included in the configuration before relying on its cache
  3. As a workaround while isolating the problem, temporarily replace cache-ref with a local <cache/> declaration

Example fix

<!-- before: CommonMapper.xml has no cache -->
<cache-ref namespace="com.acme.CommonMapper"/>
<!-- after: declare a cache in CommonMapper.xml -->
<cache/>
Defensive patterns

Strategy: validation

Validate before calling

// Verify all cache-ref namespaces resolved after factory build
Configuration cfg = factory.getConfiguration();
// incomplete refs are gone only when resolved; assert none linger:
if (!cfg.getIncompleteCacheRefs().isEmpty()) {
  throw new IllegalStateException("Unresolved cache-refs: " + cfg.getIncompleteCacheRefs());
}

Prevention

When it happens

Trigger: A mapper with <cache-ref namespace="X"/> where X's cache is not yet registered when the mapper's <select>/<insert>/... elements are processed; the statement build aborts here and the incomplete statement is queued for retry.

Common situations: Normal cross-mapper cache-ref ordering at startup (usually resolves on retry), or a permanent failure combining a dangling cache-ref with statements — the final error surfaced to the user is typically this one at the end of configuration parsing.

Related errors


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