{"record":{"id":"4841f9dac6b4e366","repo":"apache/shardingsphere","slug":"duplicate-rule-tag-s-in-file-s","errorCode":null,"errorMessage":"Duplicate rule tag `!%s` in file `%s`","messagePattern":"Duplicate rule tag `!(.+?)` in file `(.+?)`","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/config/ProxyConfigurationLoader.java","lineNumber":179,"sourceCode":"        YamlProxyDatabaseConfiguration result = YamlEngine.unmarshal(yamlFile, YamlProxyDatabaseConfiguration.class);\n        if (result.isEmpty()) {\n            return Optional.empty();\n        }\n        Preconditions.checkNotNull(result.getDatabaseName(), \"Property `databaseName` in file `%s` is required.\", yamlFile.getName());\n        DatabaseNameValidator.validate(result.getDatabaseName());\n        checkDuplicateRule(result.getRules(), yamlFile);\n        return Optional.of(result);\n    }\n    \n    private static void checkDuplicateRule(final Collection<YamlRuleConfiguration> ruleConfigs, final File yamlFile) {\n        if (ruleConfigs.isEmpty()) {\n            return;\n        }\n        Map<Class<? extends RuleConfiguration>, Long> ruleConfigTypeCountMap = ruleConfigs.stream()\n                .collect(Collectors.groupingBy(YamlRuleConfiguration::getRuleConfigurationType, Collectors.counting()));\n        Optional<Entry<Class<? extends RuleConfiguration>, Long>> duplicateRuleConfig = ruleConfigTypeCountMap.entrySet().stream().filter(each -> each.getValue() > 1L).findFirst();\n        if (duplicateRuleConfig.isPresent()) {\n            throw new IllegalStateException(String.format(\"Duplicate rule tag `!%s` in file `%s`\", getDuplicateRuleTagName(duplicateRuleConfig.get().getKey()), yamlFile.getName()));\n        }\n    }\n    \n    @SuppressWarnings(\"rawtypes\")\n    private static Object getDuplicateRuleTagName(final Class<? extends RuleConfiguration> ruleConfigClass) {\n        Optional<YamlRuleConfigurationSwapper> result = ShardingSphereServiceLoader.getServiceInstances(YamlRuleConfigurationSwapper.class)\n                .stream().filter(each -> ruleConfigClass.equals(each.getTypeClass())).findFirst();\n        return result.orElseThrow(() -> new IllegalStateException(\"Not find rule tag name of class \" + ruleConfigClass));\n    }\n    \n    private static File[] findRuleConfigurationFiles(final File path) {\n        return path.listFiles(each -> DATABASE_CONFIG_FILE_PATTERN.matcher(each.getName()).matches() || COMPATIBLE_DATABASE_CONFIG_FILE_PATTERN.matcher(each.getName()).matches());\n    }\n}\n","sourceCodeStart":161,"sourceCodeEnd":194,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/config/ProxyConfigurationLoader.java#L161-L194","documentation":"Thrown by ProxyConfigurationLoader.checkDuplicateRule when a single database YAML file declares two or more rule configurations of the same type (same !<TAG> rule tag). The loader groups YamlRuleConfiguration swapper targets by rule configuration class and counts; any count > 1 aborts startup with IllegalStateException naming the duplicated tag and file. It prevents ambiguous rule sets where later entries would silently override earlier ones.","triggerScenarios":"A database-*.yaml containing e.g. two !SHARDING blocks (or two !ENCRYPT blocks) — the YAML snakeyaml tag prefix '!SHARDING' instantiates the same YamlRuleConfiguration class twice, so getRuleConfigurationType counts collide and the Optional<Entry> filter finds the duplicate.","commonSituations":"Hand-merging config files during migration to standalone mode (concatenating two files end-to-end duplicates the tag); copy-pasting an encrypt/sharding block as a template and forgetting to change its type; repo-managed conf under proxy/conf growing duplicates over time.","solutions":["Open the named file and merge the two blocks with the same rule tag into one configuration (combine their tables/rules lists)","Delete the stale duplicate block if it was left from a copy-paste","If you need multiple rules of the same feature, put them inside the single tag's collection, not as a second top-level tag","Validate proxy conf YAML with a duplicate-tag lint before deployment"],"exampleFix":"# before (database-xxx.yaml)\nrules:\n- !SHARDING\n  tables: ...\n- !SHARDING\n  tables: [t2]\n\n# after\nrules:\n- !SHARDING\n  tables: [t1, t2]  # merged into one block","handlingStrategy":"validation","validationCode":"// Pre-flight: fail fast on duplicate rule tags before proxy startup\nYamlConfiguration yaml = loadYaml(file);\nMap<String, Long> tagCounts = yaml.getRules().stream()\n    .collect(Collectors.groupingBy(r -> r.getClass().getSimpleName(), Collectors.counting()));\ntagCounts.forEach((tag, n) -> { if (n > 1) throw new IllegalStateException(\"Duplicate rule tag \" + tag + \" in \" + file); });","typeGuard":null,"tryCatchPattern":"try {\n    ProxyConfigurationLoader.loadConfig(dir);\n} catch (IllegalStateException e) {\n    // message names the duplicated tag + file; merge the two blocks into one and restart\n    failStartupWithFixHint(e.getMessage());\n}","preventionTips":["One top-level rule tag per feature per database YAML; put multiple rules inside that block","Lint proxy conf/ for duplicate tags in CI before deploy","Never concatenate two config files blindly during migration; merge their rules lists"],"tags":["proxy","configuration","yaml","duplicate-rule","startup"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}