JetBrains/intellij-community · error · ContractConversionException
changeSignature.contract.converter.invalid.clause
changeSignature.contract.converter.invalid.clause
Error message
Invalid contract clause '{0}' What it means
Thrown by the private convertContract(StandardMethodContract, ...) in ContractConverter when a parsed contract clause's parameter count does not match the number of parameters in the old signature being refactored (contract.getParameterCount() != oldToNewIndex.length). The clause cannot be mapped onto the new parameter list, so Change Signature aborts with ContractConversionException.
Source
Thrown at java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java:73
}
int[] newToOldIndex = StreamEx.of(newParameters).mapToInt(ParameterInfo::getOldIndex).toArray();
int[] oldToNewIndex = reverseIndex(oldParameterNames.length, newToOldIndex);
List<StandardMethodContract> result = new ArrayList<>();
for (StandardMethodContract contract : contracts) {
result.add(convertContract(contract, newToOldIndex, oldToNewIndex, oldParameterNames));
}
if (result.equals(contracts)) return annotation;
return JavaMethodContractUtil.updateContract(annotation, result);
}
private static @NotNull StandardMethodContract convertContract(@NotNull StandardMethodContract contract,
int @NotNull [] newToOldIndex,
int @NotNull [] oldToNewIndex,
String @NotNull [] oldParameterNames) throws ContractConversionException {
if (contract.getParameterCount() != oldToNewIndex.length) {
// invalid contract
throw new ContractConversionException(JavaRefactoringBundle.message("changeSignature.contract.converter.invalid.clause", contract));
}
for (int i = 0; i < contract.getParameterCount(); i++) {
if (contract.getParameterConstraint(i) != StandardMethodContract.ValueConstraint.ANY_VALUE && oldToNewIndex[i] == -1) {
String paramRemovedMessage = JavaRefactoringBundle.message("changeSignature.contract.converter.parameter.removed",
oldParameterNames[i], contract);
throw new ContractConversionException(paramRemovedMessage);
}
}
StandardMethodContract.ValueConstraint[] newConstraints = IntStreamEx.of(newToOldIndex)
.mapToObj(idx -> idx == -1 ? StandardMethodContract.ValueConstraint.ANY_VALUE : contract.getParameterConstraint(idx))
.toArray(StandardMethodContract.ValueConstraint.class);
ContractReturnValue returnValue = contract.getReturnValue();
if (returnValue instanceof ContractReturnValue.ParameterReturnValue) {
int oldIndex = ((ContractReturnValue.ParameterReturnValue)returnValue).getParameterNumber();
if (oldIndex >= contract.getParameterCount()) {
String errorRefMessage = JavaRefactoringBundle.message("changeSignature.contract.converter.invalid.return.reference", returnValue);
throw new ContractConversionException(errorRefMessage);
}View on GitHub (pinned to be881553f2)
Solutions
- Update the @Contract value so every clause has exactly one constraint per parameter of the current signature, using '_' for don't-care positions.
- If parameters were added, extend each clause, e.g. two-param 'null, _ -> fail' becomes 'null, _, _ -> fail' after adding a third parameter.
- Re-run Change Signature after the annotation matches the current signature.
Example fix
// before (3 params, 2-constraint clause)
@Contract("null, _ -> fail")
void f(String a, Object b, Object c) { ... }
// after
@Contract("null, _, _ -> fail")
void f(String a, Object b, Object c) { ... } Defensive patterns
Strategy: validation
Validate before calling
String text = AnnotationUtil.getStringAttributeValue(annotation, null);
if (text != null) {
for (StandardMethodContract c : StandardMethodContract.parseContract(text)) {
if (c.getParameterCount() != method.getParameterList().getParametersCount()) {
// clause arity mismatch; fix annotation before Change Signature
}
}
} Try / catch
try { ContractConverter.convertContract(method, info); } catch (ContractConversionException e) { /* align each clause's constraint count with parameter count, retry */ } Prevention
- Keep exactly one constraint per parameter per clause; use '_' for don't-care.
- Whenever you add/remove a parameter, update all clauses of the @Contract in the same commit.
- Add a CI grep/inspection that flags @Contract arity drift on annotated methods.
When it happens
Trigger: Running Change Signature on a method where each @Contract clause lists more or fewer comma-separated constraints than the method currently has parameters — typically because parameters were already added/removed from the method (or an override) without updating the annotation.
Common situations: Method signature edited (parameter added/removed) while @Contract kept the old arity; different overrides of the same hierarchy carrying contracts of mismatched arity; generated code where contract strings are stale.
Related errors
- changeSignature.contract.converter.external.annotations
- changeSignature.contract.converter.inherited.annotation
- changeSignature.contract.converter.mutation.contract
- changeSignature.contract.converter.definition.error
- changeSignature.contract.converter.parameter.removed
AI-assisted analysis of JetBrains/intellij-community@be881553f2 (2026-08-14).
Data as JSON: /api/errors/87084a2bc289a6c0.
Report an issue: GitHub.