pentaho/pentaho-kettle · error · KettleException

No field or getter defined for

Error message

No field or getter defined for <rootClass>

What it means

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.

Solutions

  1. Add the missing field or getter for the property referenced by the injection path
  2. Fix the @Injection annotation path (name/group/ancestorPath) to match an existing field or getter
  3. Regenerate/refresh injection metadata if the bean class changed between versions
  4. Inspect BeanLevelInfo resolution for the root class to find which path element fails

Example fix

// before
class Root { /* no getter for 'connection' but path injects root.connection.host */ }
// after
class Root { public Connection getConnection() { return connection; } private Connection connection; }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check injection path elements resolve to fields or getters
for (String part : path.split("/")) {
  boolean resolvable = hasFieldOrGetter(bean.getClass(), part);
  if (!resolvable) throw new IllegalStateException(
    "Injection path element not found on " + bean.getClass().getName() + ": " + part);
}

Type guard

static boolean hasFieldOrGetter(Class<?> c, String prop) {
  for (Field f : c.getFields()) if (f.getName().equals(prop)) return true;
  for (Method m : c.getMethods())
    if ((m.getName().startsWith("get") || m.getName().startsWith("is"))
        && m.getParameterCount() == 0) return true;
  return false;
}

Try / catch

try {
  injector.injectValue(bean, path, value);
} catch (KettleException e) {
  if (e.getMessage().startsWith("No field or getter")) {
    log.error("Injection metadata mismatch on " + e.getMessage(), e);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/1ee62557b4a29b2e. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/core/injection/bean/BeanInjector.java:267

            if ( s.field != null ) {
              next = s.field.get( obj );
              if ( next == null ) {
                next = createObject( s.leafClass, root );
                s.field.set( obj, next );
              }
              obj = next;
            } else if ( s.getter != null ) {
              next = s.getter.invoke( obj );
              if ( next == null ) {
                if ( s.setter == null ) {
                  throw new KettleException( "No setter defined for " + root.getClass() );
                }
                next = s.leafClass.newInstance();
                s.setter.invoke( obj, next );
              }
              obj = next;
            } else {
              throw new KettleException( "No field or getter defined for " + root.getClass() );
            }
            break;
        }
      } else {
        // set to latest field
        if ( !s.convertEmpty ) {
          if ( data != null ) {
            if ( data.isEmptyValue( dataName ) ) {
              return true;
            }
          } else {
            if ( dataValue == null ) {
              return true;
            }
          }
        }
        if ( s.setter != null ) {
          // usual setter

View on GitHub (pinned to f3058517a1)