{"record":{"id":"b726a5bb429b559e","repo":"baomidou/mybatis-plus","slug":"detected-conflicting-annotations-s-and-s-on","errorCode":null,"errorMessage":"Detected conflicting annotations '%s' and '%s' on '%s'.","messagePattern":"Detected conflicting annotations '(.+?)' and '(.+?)' on '(.+?)'\\.","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperAnnotationBuilder.java","lineNumber":605,"sourceCode":"\n    private SqlSource buildSqlSourceFromStrings(String[] strings, Class<?> parameterTypeClass,\n                                                LanguageDriver languageDriver) {\n        return languageDriver.createSqlSource(configuration, String.join(\" \", strings).trim(), parameterTypeClass);\n    }\n\n    @SafeVarargs\n    private final Optional<AnnotationWrapper> getAnnotationWrapper(Method method, boolean errorIfNoMatch,\n                                                                                           Class<? extends Annotation>... targetTypes) {\n        return getAnnotationWrapper(method, errorIfNoMatch, Arrays.asList(targetTypes));\n    }\n\n    private Optional<AnnotationWrapper> getAnnotationWrapper(Method method, boolean errorIfNoMatch,\n                                                                                     Collection<Class<? extends Annotation>> targetTypes) {\n        String databaseId = configuration.getDatabaseId();\n        Map<String, AnnotationWrapper> statementAnnotations = targetTypes.stream()\n            .flatMap(x -> Arrays.stream(method.getAnnotationsByType(x))).map(AnnotationWrapper::new)\n            .collect(Collectors.toMap(AnnotationWrapper::getDatabaseId, x -> x, (existing, duplicate) -> {\n                throw new BuilderException(\n                    String.format(\"Detected conflicting annotations '%s' and '%s' on '%s'.\", existing.getAnnotation(),\n                        duplicate.getAnnotation(), method.getDeclaringClass().getName() + \".\" + method.getName()));\n            }));\n        AnnotationWrapper annotationWrapper = null;\n        if (databaseId != null) {\n            annotationWrapper = statementAnnotations.get(databaseId);\n        }\n        if (annotationWrapper == null) {\n            annotationWrapper = statementAnnotations.get(\"\");\n        }\n        if (errorIfNoMatch && annotationWrapper == null && !statementAnnotations.isEmpty()) {\n            // Annotations exist, but there is no matching one for the specified databaseId\n            throw new BuilderException(String.format(\n                \"Could not find a statement annotation that correspond a current database or default statement on method '%s.%s'. Current database id is [%s].\",\n                method.getDeclaringClass().getName(), method.getName(), databaseId));\n        }\n        return Optional.ofNullable(annotationWrapper);\n    }","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperAnnotationBuilder.java#L587-L623","documentation":"Thrown while collecting statement annotations on a mapper method when two annotations of the same category (e.g. two @Select annotations via repeatable containers, or @Select variants for different databaseId values) map to the same databaseId key. The builder groups annotations by their databaseId into a map; a duplicate key invokes the merge function, which raises this BuilderException naming both conflicting annotations and the method.","triggerScenarios":"Declaring two @Select(databaseId = \"mysql\", ...) annotations with the same databaseId on one method; stacking a plain @Select plus a databaseId-qualified @Select where both resolve to the empty-string default databaseId key.","commonSituations":"Adding vendor-specific statement variants while copying an existing annotation and forgetting to change databaseId; mixing repeatable annotations with the container annotation @SelectList directly; annotation duplicated by merge conflicts.","solutions":["Inspect the method named in the message and remove or correct one of the duplicate annotations so each databaseId occurs at most once.","Use distinct databaseId values per vendor (e.g. @Select(databaseId=\"mysql\") and @Select(databaseId=\"oracle\")).","Register a DatabaseIdProvider in configuration so databaseId-based routing actually works as intended."],"exampleFix":"// before\n@Select(databaseId = \"mysql\", value = \"SELECT ...\")\n@Select(databaseId = \"mysql\", value = \"SELECT /*v2*/ ...\")\nList<User> list();\n\n// after\n@Select(databaseId = \"mysql\", value = \"SELECT ...\")\n@Select(databaseId = \"oracle\", value = \"SELECT ... FROM dual\")\nList<User> list();","handlingStrategy":"validation","validationCode":"// detect two same-databaseId statement annotations on a method\nfor (java.lang.reflect.Method m : mapper.getMethods()) {\n    Map<String, Integer> ids = new java.util.HashMap<>();\n    for (java.lang.annotation.Annotation a : m.getAnnotations()) {\n        try {\n            java.lang.reflect.Method dbId = a.annotationType().getMethod(\"databaseId\");\n            String k = (String) dbId.invoke(a);\n            if (!ids.merge(k == null ? \"\" : k, 1, Integer::sum).equals(1)) {\n                throw new IllegalStateException(\"Duplicate databaseId '\" + k + \"' on \" + m);\n            }\n        } catch (NoSuchMethodException ignored) { }\n    }\n}","typeGuard":null,"tryCatchPattern":"Catch BuilderException whose message contains 'Detected conflicting annotations'; the method and both annotations are named — deduplicate and rebuild.","preventionTips":["Use at most one annotation per databaseId per method.","Configure a DatabaseIdProvider and test both database profiles in CI."],"tags":["mybatis","mybatis-plus","annotation","databaseid","configuration"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}