apache/cassandra · error · ConfigurationException
Invalid annotations, you have more than one @Replaces…
Error message
Invalid annotations, you have more than one @Replaces annotation in Config class with same old name(<oldName>) defined.
What it means
Replacements.getNameReplacements() builds the map of deprecated->new config names from @Replaces annotations on Config fields. If two fields' @Replaces annotations declare the same oldName, the mapping would be ambiguous, so it throws ConfigurationException. This is a developer-facing error when authoring Config definitions, not an operator config problem.
Solutions
- Remove or change the duplicate @Replaces(oldName=...) so each old name maps to exactly one field
- Search Config.java for the offending old name to find the conflicting annotations
- If intentional, consolidate the migration logic into a single field's @Replaces
Example fix
// before
@Replaces("old_setting") public volatile int newSettingA;
@Replaces("old_setting") public volatile int newSettingB;
// after
@Replaces("old_setting") public volatile int newSettingA; // only one replaces each old name Defensive patterns
Strategy: validation
Validate before calling
Set<String> seen = new HashSet<>();
for (Field f : Config.class.getDeclaredFields()) {
Replaces r = f.getAnnotation(Replaces.class);
if (r != null && !seen.add(r.oldName()))
throw new IllegalStateException("Duplicate @Replaces oldName: " + r.oldName());
} Try / catch
try { Map<String, Replacement> m = Replacements.getNameReplacements(...); }
catch (ConfigurationException e) { throw new IllegalStateException("Fix duplicate @Replaces annotations: " + e.getMessage()); } Prevention
- Grep Config.java for @Replaces(oldName = "x") before adding a new replacement for x
- Keep a single owner field per deprecated setting name
- Review merge conflicts touching @Replaces annotations carefully
When it happens
Trigger: Adding a field to Config with @Replaces(oldName = "x") when another field already replaces oldName "x".
Common situations: Merging upstream patches that both introduce a replacement for the same deprecated setting; copy-pasting a @Replaces annotation without changing oldName; refactoring a renamed setting twice.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- a hints file cannot be configured for both compression and…
- A maximum number of tokens per node is supported
- accord.cache_size option was set incorrectly to
- accord.journal_directory must be specified
- accord.journal_directory must not be the same as any…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/c1a316e15b937adc.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/config/Replacements.java:52
{
}
/**
* @param klass to get replacements for
* @return map of old names and replacements needed.
*/
public static Map<Class<? extends Object>, Map<String, Replacement>> getNameReplacements(Class<? extends Object> klass)
{
List<Replacement> replacements = getReplacementsRecursive(klass);
Map<Class<?>, Map<String, Replacement>> objectOldNames = new HashMap<>();
for (Replacement r : replacements)
{
Map<String, Replacement> oldNames = objectOldNames.computeIfAbsent(r.parent, ignore -> new HashMap<>());
if (!oldNames.containsKey(r.oldName))
oldNames.put(r.oldName, r);
else
{
throw new ConfigurationException("Invalid annotations, you have more than one @Replaces annotation in " +
"Config class with same old name(" + r.oldName + ") defined.");
}
}
return objectOldNames;
}
/**
* @param klass to get replacements for
* @return map of old names and replacements needed.
*/
private static List<Replacement> getReplacementsRecursive(Class<?> klass)
{
Set<Class<?>> seen = new HashSet<>(); // to make sure not to process the same type twice
List<Replacement> accum = new ArrayList<>();
getReplacementsRecursive(seen, accum, klass);
return accum.isEmpty() ? Collections.emptyList() : accum;
}
View on GitHub (pinned to 88fd0f6a0e)