NationalSecurityAgency/ghidra · error · IllegalArgumentException
Cannot apply {} to both parameters of {}
Error message
Cannot apply {} to both parameters of {} What it means
Thrown by AutoOptionsListener.MethodOptionSetter when a two-parameter @AutoOptionConsumed method annotates BOTH parameters with @NewValue. The framework maps old/new values to parameters by annotation position; applying @NewValue to both leaves no slot for the old value and is ambiguous, so it is rejected. The message names the annotation class and method.
Source
Thrown at Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptionsListener.java:135
method.setAccessible(true);
Parameter[] parameters = method.getParameters();
if (parameters.length == 0) {
this.order = ParamOrder.NONE;
}
else if (parameters.length == 1) {
if (parameters[0].getAnnotation(OldValue.class) != null) {
this.order = ParamOrder.OLD_ONLY;
}
else {
this.order = ParamOrder.NEW_ONLY;
}
}
else if (parameters.length == 2) {
if (parameters[0].getAnnotation(NewValue.class) != null) {
if (parameters[1].getAnnotation(NewValue.class) != null) {
throw new IllegalArgumentException("Cannot apply " +
NewValue.class.getName() + " to both parameters of " + method);
}
this.order = ParamOrder.NEW_OLD;
}
else if (parameters[0].getAnnotation(OldValue.class) != null) {
if (parameters[1].getAnnotation(OldValue.class) != null) {
throw new IllegalArgumentException("Cannot apply " +
OldValue.class.getName() + " to both parameters of " + method);
}
this.order = ParamOrder.OLD_NEW;
}
else {
if (parameters[1].getAnnotation(NewValue.class) != null) {
this.order = ParamOrder.OLD_NEW;
}
else {
this.order = ParamOrder.NEW_OLD;
}View on GitHub (pinned to d5f144c24d)
Solutions
- Annotate at most one parameter with @NewValue; mark the other with @OldValue or leave it unannotated.
- Use a single-parameter method if only the new value is needed.
- Review the two-parameter contract: one slot is the new value, the other the old value.
Example fix
// before
@AutoOptionConsumed("my.opt")
void onChange(@NewValue int a, @NewValue int b) { ... } // both @NewValue
// after
@AutoOptionConsumed("my.opt")
void onChange(@OldValue int oldVal, @NewValue int newVal) { ... } Defensive patterns
Strategy: validation
Validate before calling
long newCount = Arrays.stream(method.getParameters())
.filter(p -> p.getAnnotation(NewValue.class) != null).count();
if (newCount > 1) {
throw new IllegalStateException("Only one @NewValue per method: " + method);
} Prevention
- Annotate at most one parameter with @NewValue.
- Review annotations when editing method signatures.
- Add a wiring unit test that constructs the AutoOptionsListener for the plugin.
When it happens
Trigger: Annotating a method like void changed(@NewValue String a, @NewValue String b) — both params marked as the new value. Copy-paste annotation errors where both parameters receive the same annotation.
Common situations: Misunderstanding the @NewValue/@OldValue parameter-mapping contract; editing a method signature and re-annotating both params identically; IDE auto-annotation applying to all params.
Related errors
- Could not determine option type from default value: {} = {}
- {}-annotated method {} cannot have more than two parameters
- editor class must have accessible default constructor
- Service receiver method may take only one parameter
- Unsupported value: {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/760d0dfe99bfe755.
Report an issue: GitHub.