apache/shardingsphere · critical · IllegalStateException

Duplicate rule tag `!%s` in file `%s`

Error message

Duplicate rule tag `!%s` in file `%s`

What it means

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.

Source

Thrown at proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/config/ProxyConfigurationLoader.java:179

        YamlProxyDatabaseConfiguration result = YamlEngine.unmarshal(yamlFile, YamlProxyDatabaseConfiguration.class);
        if (result.isEmpty()) {
            return Optional.empty();
        }
        Preconditions.checkNotNull(result.getDatabaseName(), "Property `databaseName` in file `%s` is required.", yamlFile.getName());
        DatabaseNameValidator.validate(result.getDatabaseName());
        checkDuplicateRule(result.getRules(), yamlFile);
        return Optional.of(result);
    }
    
    private static void checkDuplicateRule(final Collection<YamlRuleConfiguration> ruleConfigs, final File yamlFile) {
        if (ruleConfigs.isEmpty()) {
            return;
        }
        Map<Class<? extends RuleConfiguration>, Long> ruleConfigTypeCountMap = ruleConfigs.stream()
                .collect(Collectors.groupingBy(YamlRuleConfiguration::getRuleConfigurationType, Collectors.counting()));
        Optional<Entry<Class<? extends RuleConfiguration>, Long>> duplicateRuleConfig = ruleConfigTypeCountMap.entrySet().stream().filter(each -> each.getValue() > 1L).findFirst();
        if (duplicateRuleConfig.isPresent()) {
            throw new IllegalStateException(String.format("Duplicate rule tag `!%s` in file `%s`", getDuplicateRuleTagName(duplicateRuleConfig.get().getKey()), yamlFile.getName()));
        }
    }
    
    @SuppressWarnings("rawtypes")
    private static Object getDuplicateRuleTagName(final Class<? extends RuleConfiguration> ruleConfigClass) {
        Optional<YamlRuleConfigurationSwapper> result = ShardingSphereServiceLoader.getServiceInstances(YamlRuleConfigurationSwapper.class)
                .stream().filter(each -> ruleConfigClass.equals(each.getTypeClass())).findFirst();
        return result.orElseThrow(() -> new IllegalStateException("Not find rule tag name of class " + ruleConfigClass));
    }
    
    private static File[] findRuleConfigurationFiles(final File path) {
        return path.listFiles(each -> DATABASE_CONFIG_FILE_PATTERN.matcher(each.getName()).matches() || COMPATIBLE_DATABASE_CONFIG_FILE_PATTERN.matcher(each.getName()).matches());
    }
}

View on GitHub (pinned to e952770a21)

Solutions

  1. Open the named file and merge the two blocks with the same rule tag into one configuration (combine their tables/rules lists)
  2. Delete the stale duplicate block if it was left from a copy-paste
  3. If you need multiple rules of the same feature, put them inside the single tag's collection, not as a second top-level tag
  4. Validate proxy conf YAML with a duplicate-tag lint before deployment

Example fix

# before (database-xxx.yaml)
rules:
- !SHARDING
  tables: ...
- !SHARDING
  tables: [t2]

# after
rules:
- !SHARDING
  tables: [t1, t2]  # merged into one block
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: fail fast on duplicate rule tags before proxy startup
YamlConfiguration yaml = loadYaml(file);
Map<String, Long> tagCounts = yaml.getRules().stream()
    .collect(Collectors.groupingBy(r -> r.getClass().getSimpleName(), Collectors.counting()));
tagCounts.forEach((tag, n) -> { if (n > 1) throw new IllegalStateException("Duplicate rule tag " + tag + " in " + file); });

Try / catch

try {
    ProxyConfigurationLoader.loadConfig(dir);
} catch (IllegalStateException e) {
    // message names the duplicated tag + file; merge the two blocks into one and restart
    failStartupWithFixHint(e.getMessage());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/4841f9dac6b4e366. Report an issue: GitHub.