pentaho/pentaho-kettle · error · KettleException
No field or setter defined for
Error message
No field or setter defined for <rootClass>
What it means
BeanInjector.setProperty() reached a leaf value to set, but the resolved BeanLevelInfo has no settable field or setter (setterStrategy NONE was unreachable because the field/setter was absent). The injector throws this KettleException naming the root class.
Solutions
- Add a setter (or make the field accessible) for the annotated property
- Set the correct setterStrategy in the @Injection annotation if the property is intentionally read-only
- Align the injection metadata with the actual bean API
Example fix
// before
@Injection(name="TIMEOUT") private long timeout; // no setter, private
// after
@Injection(name="TIMEOUT") private long timeout;
public void setTimeout(long t){ this.timeout = t; } Defensive patterns
Strategy: validation
Validate before calling
// Ensure every @Injection-annotated property has a writable accessor
for (Field f : bean.getClass().getDeclaredFields()) {
if (f.isAnnotationPresent(Injection.class)) {
boolean writable = isPublic(f) || setterExists(bean.getClass(), f.getName());
if (!writable) throw new IllegalStateException("No setter for @Injection field: " + f.getName());
}
} Type guard
static boolean setterExists(Class<?> c, String field) {
String n = "set" + Character.toUpperCase(field.charAt(0)) + field.substring(1);
try { return c.getMethod(n, c.getDeclaredField(field).getType()) != null; }
catch (NoSuchMethodException | NoSuchFieldException e) { return false; }
} Try / catch
try {
injector.injectValue(bean, path, value);
} catch (KettleException e) {
if (e.getMessage().startsWith("No field or setter")) {
log.error("Property not writable: check setter on " + e.getMessage(), e);
} else throw e;
} Prevention
- Pair every @Injection field with a setter or make it public
- Never mark injected fields final
- Add reflection-based annotation/field sanity tests
When it happens
Trigger: Injecting a value into a property whose @Injection annotation resolves to a level where the field is not settable (no public field, no setter, and not an NONE/getter-only read target being written).
Common situations: Adding @Injection to a final/private field without a setter; annotation copied from a read-only getter-only property; class refactor removed a setter.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Can't create object
- Constructor not found for
- No field or getter defined for
- Clone not supported for
- CustomVfsSettingsParser.Log.FailedToLoad
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/55cb0cedd1960f94.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/core/injection/bean/BeanInjector.java:322
// out of array for constant
return false;
}
Array.set( existArray, index, value );
break;
case LIST:
List<Object> existList = data != null ? extendList( s, obj, index + 1 ) : checkList( s, obj, index );
if ( existList == null ) {
// out of array for constant
return false;
}
existList.set( index, value );
break;
case NONE:
s.field.set( obj, value );
break;
}
} else {
throw new KettleException( "No field or setter defined for " + root.getClass() );
}
}
}
return true;
}
private Object createObject( Class<?> clazz, Object root ) throws KettleException {
try {
// Object can be inner of metadata class. In this case constructor will require parameter
for ( Constructor<?> c : clazz.getConstructors() ) {
if ( c.getParameterTypes().length == 0 ) {
return clazz.newInstance();
} else if ( c.getParameterTypes().length == 1 && c.getParameterTypes()[0].isAssignableFrom( info.clazz ) ) {
return c.newInstance( root );
}
}
} catch ( Throwable ex ) {
throw new KettleException( "Can't create object " + clazz, ex );View on GitHub (pinned to f3058517a1)