chinabugotech/hutool · error · IllegalArgumentException

Record class [] has no components

Error message

Record class [] has no components

What it means

RecordUtil.newInstance(recordClass, valueProvider) instantiates a Java record via its canonical constructor using component values from the provider. If the record declares no components (an empty record), getRecordComponents returns an empty array and the method throws IllegalArgumentException because there is nothing to populate. Note the message hardcodes the class name in brackets.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/bean/RecordUtil.java:102

				ReflectUtil.invoke(components[i], METHOD_COMPONENT_GET_NAME),
				ReflectUtil.invoke(components[i], METHOD_COMPONENT_GET_GENERIC_TYPE)
			);
		}

		return entries;
	}

	/**
	 * 实例化Record类
	 *
	 * @param recordClass   类
	 * @param valueProvider 参数值提供器
	 * @return Record类
	 */
	public static Object newInstance(final Class<?> recordClass, final ValueProvider<String> valueProvider) {
		final Map.Entry<String, Type>[] recordComponents = getRecordComponents(recordClass);
		if(ArrayUtil.isEmpty(recordComponents)){
			throw new IllegalArgumentException("Record class [" + recordClass.getName() + "] has no components");
		}
		final Class<?>[] argTypes = new Class<?>[recordComponents.length];
		final Object[] args = new Object[recordComponents.length];
		for (int i = 0; i < args.length; i++) {
			argTypes[i] = TypeUtil.getClass(recordComponents[i].getValue());
			args[i] = valueProvider.value(recordComponents[i].getKey(), recordComponents[i].getValue());
		}

		return ReflectUtil.newInstance(recordClass, argTypes, args);
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Guard with a check: skip instantiation for records with no components (call ReflectUtil.newInstance(recordClass) directly).
  2. Verify recordClass.isRecord() and getRecordComponents().length > 0 before calling.
  3. Ensure the target type is a real record with at least one component.

Example fix

// before
Object o = RecordUtil.newInstance(EmptyRecord.class, provider);
// after
Class<?> rc = EmptyRecord.class;
Object o = RecordUtil.getRecordComponents(rc).length == 0
    ? ReflectUtil.newInstance(rc)
    : RecordUtil.newInstance(rc, provider);
Defensive patterns

Strategy: validation

Validate before calling

Class<?> rc = recordClass;
if (!rc.isRecord() || RecordUtil.getRecordComponents(rc).length == 0) throw new IllegalArgumentException("not a record with components: " + rc);

Type guard

static boolean isNonEmptyRecord(Class<?> c) { return c.isRecord() && c.getRecordComponents() != null && c.getRecordComponents().length > 0; }

Prevention

When it happens

Trigger: Calling RecordUtil.newInstance on `record Empty() {}` or any record with zero components. Also triggered if a non-record class is passed and reflection yields no record components.

Common situations: Generic record-handling utilities that accept arbitrary record types; passing a class that is not actually a record (getRecordComponents returns empty for non-records in some JVM paths).

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/1e39a5124e350b3a. Report an issue: GitHub.