projectlombok/lombok · error · AnnotationValueDecodeFail

Expected a single value, but

Error message

Expected a single value, but ${method.getName()} has an array of values

What it means

AnnotationValues.invoke() reflectsively invokes an annotation method and builds the return value. If the method's return type is NOT an array but the annotation source supplied more than one value guess, lombok throws AnnotationValueDecodeFail: the annotation declared a scalar member but was given array syntax values. This guards the contract between the annotation declaration and how it was used in source.

Solutions

  1. Make the annotation usage match the declaration: pass a single value for a scalar member (value = "x" instead of value = {"x","y"}).
  2. Or change the annotation member declaration to an array type (e.g. String[] value()) if multiple values are intended.
  3. If you are an annotation handler author, check isArray/expected.getComponentType() before expecting multiple guesses.
  4. Check library upgrade notes — annotation member types sometimes change between versions.

Example fix

// before (value() declared as String)
@MyAnn(value = {"a", "b"})
// after
@MyAnn(value = "a") // or declare String[] value() in the annotation
Defensive patterns

Strategy: validation

Validate before calling

Class<?> rt = method.getReturnType(); int n = annotationValues.getRawExpressions(method.getName()).size(); if (!rt.isArray() && n > 1) throw new IllegalStateException("Scalar member got " + n + " values");

Type guard

function isScalarUsage(memberType, guessCount) { return memberType !== 'array' && guessCount <= 1; }

Try / catch

try { T v = annotationValues.invoke(method); } catch (AnnotationValueDecodeFail e) { log.error("Value/count mismatch for " + method.getName()); }

Prevention

When it happens

Trigger: Calling invoke()/getValue on an AnnotationValues instance where method.getName() has a non-array return type but v.valueGuesses.size() > 1 — i.e. source used value={a,b} (or repeated elements) for a member declared as a scalar (e.g. String value() not String[] value()).

Common situations: Copy-pasting annotation usage where the member was changed from an array type to a scalar (or vice versa) after a library version change; hand-written annotation trees built by AST transformers supplying multiple guesses for a scalar member.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of projectlombok/lombok@6d6a3e9fec (2026-09-07). Data as JSON: /api/errors/68c28222d922b9eb. Report an issue: GitHub.

Appendix: source

Thrown at src/core/lombok/core/AnnotationValues.java:251

			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				AnnotationValue v = values.get(method.getName());
				if (v == null) {
					Object defaultValue = method.getDefaultValue();
					if (defaultValue != null) return defaultValue;
					throw makeNoDefaultFail(v, method);
				}
				
				boolean isArray = false;
				Class<?> expected = method.getReturnType();
				Object array = null;
				if (expected.isArray()) {
					isArray = true;
					expected = expected.getComponentType();
					array = Array.newInstance(expected, v.valueGuesses.size());
				}
				
				if (!isArray && v.valueGuesses.size() > 1) {
					throw new AnnotationValueDecodeFail(v, 
						"Expected a single value, but " + method.getName() + " has an array of values", -1);
				}
				
				if (v.valueGuesses.size() == 0 && !isArray) {
					Object defaultValue = method.getDefaultValue();
					if (defaultValue == null) throw makeNoDefaultFail(v, method);
					return defaultValue;
				}
				
				int idx = 0;
				for (Object guess : v.valueGuesses) {
					Object result = guess == null ? null : guessToType(guess, expected, v, idx);
					if (!isArray) {
						if (result == null) {
							Object defaultValue = method.getDefaultValue();
							if (defaultValue == null) throw makeNoDefaultFail(v, method);
							return defaultValue;
						}

View on GitHub (pinned to 6d6a3e9fec)