JetBrains/intellij-community · error · ContractConversionException
changeSignature.contract.converter.mutation.contract
changeSignature.contract.converter.mutation.contract
Error message
Annotation contains mutation contract
What it means
Thrown by ContractConverter.convertContract when the method's @Contract annotation also declares the 'mutates' attribute (org.jetbrains.annotations.MutationSignature ATTR_MUTATES, used by @MutationContract-style contracts). The converter only knows how to rewrite value contracts, not mutation contracts that reference parameters by name for mutation semantics, so it aborts with ContractConversionException.
Source
Thrown at java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java:42
private ContractConverter() {}
public static @Nullable PsiAnnotation convertContract(@NotNull PsiMethod method, @NotNull JavaChangeInfo info) throws ContractConversionException {
return convertContract(method, info.getOldParameterNames(), info.getNewParameters());
}
public static @Nullable PsiAnnotation convertContract(@NotNull PsiMethod method,
String @NotNull [] oldParameterNames,
JavaParameterInfo @NotNull [] newParameters) throws ContractConversionException {
PsiAnnotation annotation = JavaMethodContractUtil.findContractAnnotation(method);
if (annotation == null || AnnotationUtil.isInferredAnnotation(annotation)) return null;
if (AnnotationUtil.isExternalAnnotation(annotation)) {
throw new ContractConversionException(JavaRefactoringBundle.message("changeSignature.contract.converter.external.annotations"));
}
if (annotation.getOwner() != method.getModifierList()) {
throw new ContractInheritedException();
}
if (annotation.findDeclaredAttributeValue(MutationSignature.ATTR_MUTATES) != null) {
throw new ContractConversionException(JavaRefactoringBundle.message("changeSignature.contract.converter.mutation.contract"));
}
String text = AnnotationUtil.getStringAttributeValue(annotation, null);
List<StandardMethodContract> contracts = Collections.emptyList();
if (text != null) {
try {
contracts = StandardMethodContract.parseContract(text);
}
catch (StandardMethodContract.ParseException exception) {
String definitionError = JavaRefactoringBundle.message("changeSignature.contract.converter.definition.error",
exception.getMessage());
throw new ContractConversionException(definitionError);
}
}
int[] newToOldIndex = StreamEx.of(newParameters).mapToInt(ParameterInfo::getOldIndex).toArray();
int[] oldToNewIndex = reverseIndex(oldParameterNames.length, newToOldIndex);
List<StandardMethodContract> result = new ArrayList<>();
for (StandardMethodContract contract : contracts) {View on GitHub (pinned to be881553f2)
Solutions
- Temporarily remove the mutates attribute from the @Contract annotation, run Change Signature, then re-add mutates with updated parameter references.
- Update the mutation contract manually after performing the signature change without automatic conversion.
- Keep parameter order stable for methods with mutation contracts, or refactor them by hand.
Example fix
// before
@Contract(mutates = "param1", value = "null -> false")
boolean process(String a, List<String> out) { ... }
// after (manual, params reordered)
@Contract(mutates = "param2", value = "null -> false")
boolean process(List<String> out, String a) { ... } Defensive patterns
Strategy: validation
Validate before calling
PsiAnnotation a = JavaMethodContractUtil.findContractAnnotation(method);
if (a != null && a.findDeclaredAttributeValue("mutates") != null) {
// mutation contract present; plan a manual contract update around the refactoring
} Try / catch
try { ContractConverter.convertContract(method, info); } catch (ContractConversionException e) { /* if message mentions mutation contract, edit annotation manually then retry */ } Prevention
- For methods with mutates attributes, change signatures by hand and update both value and mutates strings.
- Keep parameter names stable in mutation contracts; prefer refactoring before contracts grow complex.
- Review @Contract attributes (including mutates) whenever parameters are renamed or reordered.
When it happens
Trigger: Running Change Signature on a method annotated like @Contract(mutates = "this,param1", value = "...") or any contract whose attribute set includes mutates; the signature change would require reindexing the mutation contract's parameter references.
Common situations: Code using JetBrains mutation-contract annotations on builder/mutator methods; refactoring methods annotated with both value and mutates; recent IDE versions that parse mutates make previously ignorable cases fatal.
Related errors
- changeSignature.contract.converter.external.annotations
- changeSignature.contract.converter.inherited.annotation
- changeSignature.contract.converter.definition.error
- changeSignature.contract.converter.invalid.clause
- changeSignature.contract.converter.parameter.removed
AI-assisted analysis of JetBrains/intellij-community@be881553f2 (2026-08-14).
Data as JSON: /api/errors/82ce05e7a98c7161.
Report an issue: GitHub.