mybatis/mybatis-3 · error · IllegalArgumentException

name + " already contains key " + key

Error message

name + " already contains key " + key

What it means

Configuration.StrictMap.put() rejects duplicate full keys: every mapped statement, result map, parameter map, and sql fragment is stored in a StrictMap keyed by its fully-qualified id (namespace + '.' + id). Registering a second object with the same full name throws IllegalArgumentException with the map name, the key, and an optional producer-supplied conflict detail. This is MyBatis' guard against ambiguous statement ids.

Source

Thrown at src/main/java/org/apache/ibatis/session/Configuration.java:1158

     * function arguments are 1st is saved value and 2nd is target value.
     *
     * @param conflictMessageProducer
     *          A function for producing a conflict error message
     *
     * @return a conflict error message
     *
     * @since 3.5.0
     */
    public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {
      this.conflictMessageProducer = conflictMessageProducer;
      return this;
    }

    @Override
    @SuppressWarnings("unchecked")
    public V put(String key, V value) {
      if (containsKey(key)) {
        throw new IllegalArgumentException(name + " already contains key " + key
            + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
      }
      if (key.contains(".")) {
        final String shortKey = getShortName(key);
        if (super.get(shortKey) == null) {
          super.put(shortKey, value);
        } else {
          super.put(shortKey, (V) AMBIGUITY_INSTANCE);
        }
      }
      return super.put(key, value);
    }

    @Override
    public boolean containsKey(Object key) {
      if (key == null) {
        return false;
      }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Search all mapper XML and annotation mappers for the duplicated id shown in the message and rename one of them.
  2. Ensure each file has a unique namespace (conventionally the fully-qualified mapper interface name).
  3. Remove duplicate <mapper> registrations pointing at the same resource (check mybatis-config.xml and Spring's mapperLocations/@MapperScan).
  4. If using annotations, do not duplicate an annotated method id that also exists in an XML bound to the same namespace.

Example fix

// before
<mapper namespace="com.acme.UserMapper">
  <select id="findById">...</select>
  <select id="findById">...</select>
</mapper>
// after
<mapper namespace="com.acme.UserMapper">
  <select id="findById">...</select>
  <select id="findByName">...</select>
</mapper>
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast on duplicates before adding: StrictMap already throws on put,
// so validate your XML at startup by building the Configuration once in CI.

Try / catch

try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(config); }
catch (IllegalArgumentException e) { /* message shows map name + duplicate key; rename or deregister */ throw e; }

Prevention

When it happens

Trigger: Two <select>/<insert>/<update>/<delete> with the same id in one mapper XML namespace; the same statement id in both an XML file and an annotated mapper interface method within one namespace; registering the same mapper resource twice (mybatis-config <mapper> entries duplicated, or Spring component scan + @MapperScan overlap); same resultMap id defined in two files with the same namespace.

Common situations: Merging mapper files during refactoring; copy-paste of a statement without changing its id; legacy XML mapper plus new annotation-based mapper colliding after @MapperScan is added; namespace attribute copy-pasted so two files share a namespace.

Related errors


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