JetBrains/intellij-community · error · ContractConversionException

changeSignature.contract.converter.parameter.removed

changeSignature.contract.converter.parameter.removed

Error message

Parameter '{0}' was deleted, but contract clause '{1}' depends on it

What it means

Thrown by the private convertContract in ContractConverter when a parameter that a contract clause constrains (constraint != ANY_VALUE, i.e. not '_') is removed by the Change Signature operation (oldToNewIndex[i] == -1). Dropping the parameter would silently invalidate the clause's meaning, so the refactoring refuses to proceed.

Source

Thrown at java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java:79

      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);
      }
      int index = oldToNewIndex[oldIndex];
      if (index == -1) {
        String paramRemovedMessage = JavaRefactoringBundle.message("changeSignature.contract.converter.return.parameter.removed",
                                                                   oldParameterNames[oldIndex], contract);
        throw new ContractConversionException(paramRemovedMessage);
      }

View on GitHub (pinned to be881553f2)

Solutions

  1. Instead of deleting the parameter, keep it or replace its constraint with '_' only after you delete the parameter — but the IDE requires the clause not depend on it, so first restructure the logic so the constraint is unnecessary.
  2. Split the refactoring: first edit @Contract manually to remove dependence on that parameter (change its constraint to '_'), then run Change Signature to delete the parameter.
  3. Alternatively delete the whole @Contract annotation if it is no longer meaningful after the parameter removal.

Example fix

// before: deleting 's' via Change Signature throws
@Contract("null -> fail")
void f(String s) { ... }
// after: drop the constraint first, then delete the parameter
// step 1: @Contract(" -> fail") void f(String s) -> simplify to no contract, or keep param
Defensive patterns

Strategy: validation

Validate before calling

// before deleting parameter i, check no clause constrains it
for (StandardMethodContract c : StandardMethodContract.parseContract(contractText)) {
  if (c.getParameterConstraint(i) != StandardMethodContract.ValueConstraint.ANY_VALUE) {
    // clause depends on the parameter to be deleted; adjust contract first
  }
}

Try / catch

try { ContractConverter.convertContract(method, info); } catch (ContractConversionException e) { /* relax the constraint to '_' or drop the annotation, then delete the parameter */ }

Prevention

When it happens

Trigger: Change Signature removing a parameter that appears with a real constraint (null, !null, true, false) in some @Contract clause; e.g. deleting parameter 's' from @Contract("null -> fail") boolean f(String s).

Common situations: Cleaning up 'unused' parameters that are actually load-bearing for nullability contracts; API slimming on annotated public methods; batch refactor scripts deleting parameters without checking annotations.

Related errors


AI-assisted analysis of JetBrains/intellij-community@be881553f2 (2026-08-14). Data as JSON: /api/errors/d6ef577743c7b456. Report an issue: GitHub.