JetBrains/intellij-community · error · ContractConversionException
changeSignature.contract.converter.invalid.return.reference
changeSignature.contract.converter.invalid.return.reference
Error message
Invalid reference in return value: {0} What it means
Thrown by the private convertContract in ContractConverter when a @Contract clause's return value references a parameter by number (ParameterReturnValue, e.g. '-> param1') but that number is out of range for the clause's parameter count. The return value points at a parameter that does not exist in the parsed clause, indicating a corrupt or stale contract clause.
Source
Thrown at java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java:90
// 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);
}
int index = oldToNewIndex[oldIndex];
if (index == -1) {
String paramRemovedMessage = JavaRefactoringBundle.message("changeSignature.contract.converter.return.parameter.removed",
oldParameterNames[oldIndex], contract);
throw new ContractConversionException(paramRemovedMessage);
}
returnValue = ContractReturnValue.returnParameter(index);
}
return new StandardMethodContract(newConstraints, returnValue);
}
private static int[] reverseIndex(int oldParameterCount, int[] newToOldIndex) {
int[] oldToNewIndex = new int[oldParameterCount];
Arrays.fill(oldToNewIndex, -1);
for (int i = 0; i < newToOldIndex.length; i++) {
int oldIndex = newToOldIndex[i];
if (oldIndex >= 0 && oldIndex < oldParameterCount) {View on GitHub (pinned to be881553f2)
Solutions
- Fix the return reference: paramN is 1-based, so for a method with N parameters only '-> param1'.."-> paramN" are valid.
- Align the clause's constraint count with the parameter count and the paramN reference with an existing parameter.
- Re-run Change Signature once the contract parses consistently.
Example fix
// before (2 params, references 3rd)
@Contract("null, null -> param3")
Object f(Object a, Object b) { ... }
// after
@Contract("_, null -> param2")
Object f(Object a, Object b) { return b; } Defensive patterns
Strategy: validation
Validate before calling
for (StandardMethodContract c : StandardMethodContract.parseContract(contractText)) {
ContractReturnValue rv = c.getReturnValue();
if (rv instanceof ContractReturnValue.ParameterReturnValue prv
&& prv.getParameterNumber() > c.getParameterCount()) {
// out-of-range param reference; fix the return value
}
} Try / catch
try { ContractConverter.convertContract(method, info); } catch (ContractConversionException e) { /* fix '-> paramN' to an in-range 1-based index, retry */ } Prevention
- Remember paramN in @Contract is 1-based and must be <= parameter count.
- When copying contracts between methods, re-check param references against the target's arity.
- Fix stale contracts immediately when parameters change, not at refactoring time.
When it happens
Trigger: A contract like @Contract("null -> param2") on a 2-parameter method (param index beyond the constraint list), or '-> param1' where the clause lists constraints for a different arity; running Change Signature then trips the index check oldIndex >= contract.getParameterCount().
Common situations: Hand-written paramN references miscounted from 1; parameters removed earlier leaving paramN pointing past the end; contract strings copied between similar methods with different parameter counts.
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.invalid.clause
AI-assisted analysis of JetBrains/intellij-community@be881553f2 (2026-08-14).
Data as JSON: /api/errors/457805862f2bd246.
Report an issue: GitHub.