pentaho/pentaho-kettle · error · KettleException
Can't create object
Error message
Can't create object
What it means
BeanInjector.createObject() uses reflection to instantiate a nested object along the injection path, either via a no-arg constructor or a single-arg constructor taking the root. Any reflective failure (no accessible constructor, instantiation exception) is wrapped in this KettleException.
Solutions
- Add a public no-arg constructor to the nested class
- Add a constructor taking the root bean type if contextual construction is needed
- Make the injected property type concrete (not abstract/interface)
- Catch-and-log to see the wrapped cause for why newInstance failed
Example fix
// before
class Child { Child(Root r, int extra){...} } // no matching ctor
// after
class Child { public Child(){} public Child(Root r){...} } Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the nested class has a usable constructor before injecting
Class<?> c = nestedPropertyType;
boolean ok = Arrays.stream(c.getConstructors()).anyMatch(ctor ->
ctor.getParameterCount() == 0
|| (ctor.getParameterCount() == 1 && ctor.getParameterTypes()[0].isAssignableFrom(rootClass)));
if (!ok) throw new IllegalStateException("No injectable constructor on " + c.getName()); Type guard
static boolean instantiableForInjection(Class<?> c, Class<?> root) {
if (c.isInterface() || Modifier.isAbstract(c.getModifiers())) return false;
try { c.getDeclaredConstructor(); return true; }
catch (NoSuchMethodException e) {
for (Constructor<?> k : c.getConstructors())
if (k.getParameterCount() == 1 && k.getParameterTypes()[0].isAssignableFrom(root)) return true;
return false;
}
} Try / catch
try {
injector.injectValue(bean, path, value);
} catch (KettleException e) {
if (e.getMessage().startsWith("Can't create object")) {
log.error("Failed to instantiate nested bean; cause: ", e.getCause());
} else throw e;
} Prevention
- Give every nested injection bean a public no-arg constructor
- Avoid abstract/interface types on injection path properties
- Keep constructors side-effect-free so newInstance cannot throw
When it happens
Trigger: setProperty encounters a path level whose class lacks a usable no-arg constructor or a constructor accepting the root object; constructor throws during newInstance.
Common situations: Nested bean without a default constructor; abstract class or interface in the injection path; constructor throws IllegalArgumentException on root.
Related errors
- Constructor not found for
- DefaultAuthenticationConsumerFactory.Constructor
- DefaultAuthenticationConsumerFactory.Constructor.Arg
- No field or getter defined for
- No field or setter defined for
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/d806e14178075cbc.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/core/injection/bean/BeanInjector.java:340
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 );
}
throw new KettleException( "Constructor not found for " + clazz );
}
private Object extendArray( BeanLevelInfo s, Object obj, int newSize ) throws Exception {
Object existArray = s.field.get( obj );
if ( existArray == null ) {
existArray = Array.newInstance( s.leafClass, newSize );
s.field.set( obj, existArray );
}
int existSize = Array.getLength( existArray );
if ( existSize < newSize ) {
Object newSized = Array.newInstance( s.leafClass, newSize );
System.arraycopy( existArray, 0, newSized, 0, existSize );
existArray = newSized;
s.field.set( obj, existArray );
}
View on GitHub (pinned to f3058517a1)