{"record":{"id":"2a069f03138cb37b","repo":"baomidou/mybatis-plus","slug":"s-already-contains-value-for-s","errorCode":null,"errorMessage":"%s already contains value for %s","messagePattern":"(.+?) already contains value for (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisConfiguration.java","lineNumber":454,"sourceCode":"        /**\n         * Assign a function for producing a conflict error message when contains value with the same key.\n         * <p>\n         * function arguments are 1st is saved value and 2nd is target value.\n         *\n         * @param conflictMessageProducer A function for producing a conflict error message\n         * @return a conflict error message\n         * @since 3.5.0\n         */\n        public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {\n            this.conflictMessageProducer = conflictMessageProducer;\n            return this;\n        }\n\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public V put(String key, V value) {\n            if (containsKey(key)) {\n                throw new IllegalArgumentException(name + \" already contains value for \" + key\n                    + (conflictMessageProducer == null ? StringPool.EMPTY : conflictMessageProducer.apply(super.get(key), value)));\n            }\n            if (useGeneratedShortKey) {\n                if (key.contains(StringPool.DOT)) {\n                    final String shortKey = getShortName(key);\n                    if (super.get(shortKey) == null) {\n                        super.put(shortKey, value);\n                    } else {\n                        super.put(shortKey, (V) AMBIGUITY_INSTANCE);\n                    }\n                }\n            }\n            return super.put(key, value);\n        }\n\n        @Override\n        public boolean containsKey(Object key) {\n            if (key == null) {","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisConfiguration.java#L436-L472","documentation":"Thrown by MybatisConfiguration.StrictMap.put when a duplicate key is registered in a strict map (mapper statements, result maps, sql fragments, parameter maps). MyBatis-Plus copies MyBatis's StrictMap semantics: each fully-qualified id must be unique, so re-registering an id is treated as a configuration defect rather than silently overwriting. The extra detail comes from an optional conflictMessageProducer that can show both conflicting values.","triggerScenarios":"Two XML mapper files or annotation methods defining the same statement id (e.g. 'com.example.UserMapper.selectById' in both an XML file and a @Select annotated method), or the same mapper XML loaded twice via different <mapper> entries; also registering two result maps or sql fragments with the same namespace-qualified id.","commonSituations":"Copying a mapper XML and forgetting to rename the namespace; mixing annotation-based statements with an XML file that has the same id; classpath duplication where the same mapper XML is packaged twice; switching a project to mybatis-plus while old MyBatis mapper XML files remain on the classpath.","solutions":["Search all mapper XML namespaces and annotated mapper interfaces for the duplicated statement id shown in the message and rename one of them.","If the id exists both as an annotation (@Select etc.) and in XML for the same mapper method, remove one of the two definitions.","Check for the same XML file being loaded twice (duplicate <mapper resource=...> entries in mybatis-config.xml, or the same jar included twice in the build).","If intentional overriding is required, register the overriding mapper in a different namespace instead of reusing the same id."],"exampleFix":"<!-- before: two files both declare id selectById under namespace com.example.UserMapper -->\n<mapper namespace=\"com.example.UserMapper\">\n  <select id=\"selectById\">...</select>\n</mapper>\n\n<!-- after: give the second statement a distinct id/namespace -->\n<mapper namespace=\"com.example.UserMapperXml\">\n  <select id=\"selectByIdLegacy\">...</select>\n</mapper>","handlingStrategy":"validation","validationCode":"// before building the SqlSessionFactory, assert no duplicate statement ids across mappers\nSet<String> ids = new HashSet<>();\nfor (MapperMethod-ish m : allMapperMethods) { /* illustrative */ }\n// practical check: after factory build, walk mapped statements\norg.apache.ibatis.session.Configuration cfg = factory.getConfiguration();\nSet<String> seen = new HashSet<>();\nfor (Object ms : new java.util.ArrayList<>(cfg.getMappedStatements())) {\n    if (ms instanceof org.apache.ibatis.mapping.MappedStatement) {\n        String id = ((org.apache.ibatis.mapping.MappedStatement) ms).getId();\n        if (!seen.add(id)) throw new IllegalStateException(\"Duplicate statement id: \" + id);\n    }\n}","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) when message starts with the StrictMap name + \" already contains value for\" — extract the key from the message and report the conflicting mapper files; fail startup, do not retry.","preventionTips":["One statement definition per id: keep annotations and XML mutually exclusive for the same method.","Derive XML namespaces from the mapper interface FQCN by convention.","Add a startup integration test that builds the SqlSessionFactory to catch duplicates before deploy."],"tags":["mybatis","mybatis-plus","configuration","duplicate-key","mapper"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}