pentaho/pentaho-kettle · error · KettleException

Could not locate perspective by class:

Error message

Could not locate perspective by class: 

What it means

SpoonPerspectiveManager.activatePerspective(Class<? extends SpoonPerspective>) looks up the requested perspective in its registry map and throws KettleException if no perspective is registered under that class. It means the code asked to switch to a perspective that was never installed/registered with the manager.

Solutions

  1. Confirm the perspective is registered: call addPerspective(perspective) (or ship the perspective plugin correctly) before activation
  2. Check the perspective plugin's annotation/plugin metadata so it loads at Spoon startup
  3. Guard activation with getPerspective(clazz) != null before calling activatePerspective
  4. Ensure you pass the exact registered class, not a subclass or same-named class from another classloader

Example fix

// before
manager.activatePerspective(MyPerspective.class); // throws if not registered
// after
if ( manager.getPerspective(MyPerspective.class) != null ) {
  manager.activatePerspective(MyPerspective.class);
}
Defensive patterns

Strategy: try-catch

Validate before calling

SpoonPerspective sp = manager.getPerspective(MyPerspective.class);
if (sp == null) {
  // perspective not registered — register it or skip activation
  return;
}

Type guard

boolean isRegistered(SpoonPerspectiveManager m, Class<? extends SpoonPerspective> c) {
  return m.getPerspective(c) != null;
}

Try / catch

try {
  manager.activatePerspective(MyPerspective.class);
} catch (KettleException e) {
  log.error("Perspective not registered: " + e.getMessage());
  // stay on current perspective or register lazily then retry
}

Prevention

When it happens

Trigger: Calling activatePerspective(SomePerspective.class) where the perspective instance was never added via addPerspective, the perspective plugin failed to load, or the class differs from the registered one (different classloader or subclass).

Common situations: A perspective plugin's plugin.xml/class is missing so it never registers; calling activatePerspective during startup before initialize() registered the perspectives; duplicate class instances across classloaders in an OSGi-ish plugin environment.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at ui/src/main/java/org/pentaho/di/ui/spoon/SpoonPerspectiveManager.java:302

  /**
   * Activates the given instance of the class literal passed in. Activating a perspective first deactivates the current
   * perspective removing any overlays its applied to the UI. It then switches the main deck to display the perspective
   * UI and applies the optional overlays to the main Spoon XUL container.
   *
   * @param clazz
   *          SpoonPerspective class literal
   * @throws KettleException
   *           throws a KettleException if no perspective is found for the given parameter
   */
  public void activatePerspective( Class<? extends SpoonPerspective> clazz ) throws KettleException {

    if ( this.forcePerspective ) {
      // we are currently prevented from switching perspectives
      return;
    }
    SpoonPerspective sp = perspectives.get( clazz );
    if ( sp == null ) {
      throw new KettleException( "Could not locate perspective by class: " + clazz );
    }
    PerspectiveManager perspectiveManager = getPerspectiveManagerMap().get( sp );
    if ( perspectiveManager != null ) {
      perspectiveManager.initializeIfNeeded();
    }
    unloadPerspective( activePerspective );
    activePerspective = sp;

    List<XulOverlay> overlays = sp.getOverlays();
    if ( overlays != null ) {
      for ( XulOverlay overlay : overlays ) {
        try {
          ResourceBundle res = null;
          if ( overlay.getResourceBundleUri() != null ) {
            try {
              res = GlobalMessageUtil.getBundle( overlay.getResourceBundleUri(), SpoonPerspectiveManager.class );
            } catch ( MissingResourceException ignored ) {
              // Ignore errors

View on GitHub (pinned to f3058517a1)