{"record":{"id":"55cb0cedd1960f94","repo":"pentaho/pentaho-kettle","slug":"no-field-or-setter-defined-for-rootclass","errorCode":null,"errorMessage":"No field or setter defined for <rootClass>","messagePattern":"No field or setter defined for <rootClass>","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/core/injection/bean/BeanInjector.java","lineNumber":322,"sourceCode":"                // out of array for constant\n                return false;\n              }\n              Array.set( existArray, index, value );\n              break;\n            case LIST:\n              List<Object> existList = data != null ? extendList( s, obj, index + 1 ) : checkList( s, obj, index );\n              if ( existList == null ) {\n                // out of array for constant\n                return false;\n              }\n              existList.set( index, value );\n              break;\n            case NONE:\n              s.field.set( obj, value );\n              break;\n          }\n        } else {\n          throw new KettleException( \"No field or setter defined for \" + root.getClass() );\n        }\n      }\n    }\n    return true;\n  }\n\n  private Object createObject( Class<?> clazz, Object root ) throws KettleException {\n    try {\n      // Object can be inner of metadata class. In this case constructor will require parameter\n      for ( Constructor<?> c : clazz.getConstructors() ) {\n        if ( c.getParameterTypes().length == 0 ) {\n          return clazz.newInstance();\n        } else if ( c.getParameterTypes().length == 1 && c.getParameterTypes()[0].isAssignableFrom( info.clazz ) ) {\n          return c.newInstance( root );\n        }\n      }\n    } catch ( Throwable ex ) {\n      throw new KettleException( \"Can't create object \" + clazz, ex );","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/core/injection/bean/BeanInjector.java#L304-L340","documentation":"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.","triggerScenarios":"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).","commonSituations":"Adding @Injection to a final/private field without a setter; annotation copied from a read-only getter-only property; class refactor removed a setter.","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"],"exampleFix":"// before\n@Injection(name=\"TIMEOUT\") private long timeout; // no setter, private\n// after\n@Injection(name=\"TIMEOUT\") private long timeout;\npublic void setTimeout(long t){ this.timeout = t; }","handlingStrategy":"validation","validationCode":"// Ensure every @Injection-annotated property has a writable accessor\nfor (Field f : bean.getClass().getDeclaredFields()) {\n  if (f.isAnnotationPresent(Injection.class)) {\n    boolean writable = isPublic(f) || setterExists(bean.getClass(), f.getName());\n    if (!writable) throw new IllegalStateException(\"No setter for @Injection field: \" + f.getName());\n  }\n}","typeGuard":"static boolean setterExists(Class<?> c, String field) {\n  String n = \"set\" + Character.toUpperCase(field.charAt(0)) + field.substring(1);\n  try { return c.getMethod(n, c.getDeclaredField(field).getType()) != null; }\n  catch (NoSuchMethodException | NoSuchFieldException e) { return false; }\n}","tryCatchPattern":"try {\n  injector.injectValue(bean, path, value);\n} catch (KettleException e) {\n  if (e.getMessage().startsWith(\"No field or setter\")) {\n    log.error(\"Property not writable: check setter on \" + e.getMessage(), e);\n  } else throw e;\n}","preventionTips":["Pair every @Injection field with a setter or make it public","Never mark injected fields final","Add reflection-based annotation/field sanity tests"],"tags":["reflection","bean-injection","setter"],"backgroundTag":"invalid-argument-value","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}