{"record":{"id":"1ee62557b4a29b2e","repo":"pentaho/pentaho-kettle","slug":"no-field-or-getter-defined-for-rootclass","errorCode":null,"errorMessage":"No field or getter defined for <rootClass>","messagePattern":"No field or getter 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":267,"sourceCode":"            if ( s.field != null ) {\n              next = s.field.get( obj );\n              if ( next == null ) {\n                next = createObject( s.leafClass, root );\n                s.field.set( obj, next );\n              }\n              obj = next;\n            } else if ( s.getter != null ) {\n              next = s.getter.invoke( obj );\n              if ( next == null ) {\n                if ( s.setter == null ) {\n                  throw new KettleException( \"No setter defined for \" + root.getClass() );\n                }\n                next = s.leafClass.newInstance();\n                s.setter.invoke( obj, next );\n              }\n              obj = next;\n            } else {\n              throw new KettleException( \"No field or getter defined for \" + root.getClass() );\n            }\n            break;\n        }\n      } else {\n        // set to latest field\n        if ( !s.convertEmpty ) {\n          if ( data != null ) {\n            if ( data.isEmptyValue( dataName ) ) {\n              return true;\n            }\n          } else {\n            if ( dataValue == null ) {\n              return true;\n            }\n          }\n        }\n        if ( s.setter != null ) {\n          // usual setter","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/core/injection/bean/BeanInjector.java#L249-L285","documentation":"BeanInjector.setProperty() walks the annotation-declared injection path (field/getter chain) of a @Injection-annotated bean. When a path element cannot be resolved to either a field or a getter on the current object, it throws this KettleException naming the root class. It signals a mismatch between the injection metadata and the actual bean structure.","triggerScenarios":"Calling newInjection/injectVal on a bean whose @Injection(ancestorPath/group) path references a level that has neither a field nor a getter; e.g. an intermediate path segment naming a property that does not exist on the root class.","commonSituations":"Renamed or removed fields/getters after annotations were defined; injecting plugin settings whose XML/ktr metadata references properties absent from the current class version; typos in injection group/ancestor paths.","solutions":["Add the missing field or getter for the property referenced by the injection path","Fix the @Injection annotation path (name/group/ancestorPath) to match an existing field or getter","Regenerate/refresh injection metadata if the bean class changed between versions","Inspect BeanLevelInfo resolution for the root class to find which path element fails"],"exampleFix":"// before\nclass Root { /* no getter for 'connection' but path injects root.connection.host */ }\n// after\nclass Root { public Connection getConnection() { return connection; } private Connection connection; }","handlingStrategy":"validation","validationCode":"// Pre-check injection path elements resolve to fields or getters\nfor (String part : path.split(\"/\")) {\n  boolean resolvable = hasFieldOrGetter(bean.getClass(), part);\n  if (!resolvable) throw new IllegalStateException(\n    \"Injection path element not found on \" + bean.getClass().getName() + \": \" + part);\n}","typeGuard":"static boolean hasFieldOrGetter(Class<?> c, String prop) {\n  for (Field f : c.getFields()) if (f.getName().equals(prop)) return true;\n  for (Method m : c.getMethods())\n    if ((m.getName().startsWith(\"get\") || m.getName().startsWith(\"is\"))\n        && m.getParameterCount() == 0) return true;\n  return false;\n}","tryCatchPattern":"try {\n  injector.injectValue(bean, path, value);\n} catch (KettleException e) {\n  if (e.getMessage().startsWith(\"No field or getter\")) {\n    log.error(\"Injection metadata mismatch on \" + e.getMessage(), e);\n  } else throw e;\n}","preventionTips":["Keep @Injection paths in sync with bean fields/getters; cover with unit tests using newInjection","Run injection metadata tests in CI whenever bean classes change","Prefer public getters + setters for every injected property"],"tags":["reflection","bean-injection","metadata"],"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"}