{"record":{"id":"d6cf8eb0a7e8cee4","repo":"pentaho/pentaho-kettle","slug":"could-not-locate-perspective-by-class","errorCode":null,"errorMessage":"Could not locate perspective by class: ","messagePattern":"Could not locate perspective by class: ","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"ui/src/main/java/org/pentaho/di/ui/spoon/SpoonPerspectiveManager.java","lineNumber":302,"sourceCode":"  /**\n   * Activates the given instance of the class literal passed in. Activating a perspective first deactivates the current\n   * perspective removing any overlays its applied to the UI. It then switches the main deck to display the perspective\n   * UI and applies the optional overlays to the main Spoon XUL container.\n   *\n   * @param clazz\n   *          SpoonPerspective class literal\n   * @throws KettleException\n   *           throws a KettleException if no perspective is found for the given parameter\n   */\n  public void activatePerspective( Class<? extends SpoonPerspective> clazz ) throws KettleException {\n\n    if ( this.forcePerspective ) {\n      // we are currently prevented from switching perspectives\n      return;\n    }\n    SpoonPerspective sp = perspectives.get( clazz );\n    if ( sp == null ) {\n      throw new KettleException( \"Could not locate perspective by class: \" + clazz );\n    }\n    PerspectiveManager perspectiveManager = getPerspectiveManagerMap().get( sp );\n    if ( perspectiveManager != null ) {\n      perspectiveManager.initializeIfNeeded();\n    }\n    unloadPerspective( activePerspective );\n    activePerspective = sp;\n\n    List<XulOverlay> overlays = sp.getOverlays();\n    if ( overlays != null ) {\n      for ( XulOverlay overlay : overlays ) {\n        try {\n          ResourceBundle res = null;\n          if ( overlay.getResourceBundleUri() != null ) {\n            try {\n              res = GlobalMessageUtil.getBundle( overlay.getResourceBundleUri(), SpoonPerspectiveManager.class );\n            } catch ( MissingResourceException ignored ) {\n              // Ignore errors","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/ui/src/main/java/org/pentaho/di/ui/spoon/SpoonPerspectiveManager.java#L284-L320","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Confirm the perspective is registered: call addPerspective(perspective) (or ship the perspective plugin correctly) before activation","Check the perspective plugin's annotation/plugin metadata so it loads at Spoon startup","Guard activation with getPerspective(clazz) != null before calling activatePerspective","Ensure you pass the exact registered class, not a subclass or same-named class from another classloader"],"exampleFix":"// before\nmanager.activatePerspective(MyPerspective.class); // throws if not registered\n// after\nif ( manager.getPerspective(MyPerspective.class) != null ) {\n  manager.activatePerspective(MyPerspective.class);\n}","handlingStrategy":"try-catch","validationCode":"SpoonPerspective sp = manager.getPerspective(MyPerspective.class);\nif (sp == null) {\n  // perspective not registered — register it or skip activation\n  return;\n}","typeGuard":"boolean isRegistered(SpoonPerspectiveManager m, Class<? extends SpoonPerspective> c) {\n  return m.getPerspective(c) != null;\n}","tryCatchPattern":"try {\n  manager.activatePerspective(MyPerspective.class);\n} catch (KettleException e) {\n  log.error(\"Perspective not registered: \" + e.getMessage());\n  // stay on current perspective or register lazily then retry\n}","preventionTips":["Register every perspective via addPerspective before any activation call","Verify perspective plugin metadata so it loads at Spoon startup","Call activation only after the manager is fully initialized","Use the exact registered class (mind plugin classloaders)"],"tags":["perspective","registry-miss","spoon"],"backgroundTag":"resource-not-found","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"}