{"record":{"id":"f531b85828b06026","repo":"pentaho/pentaho-kettle","slug":"unable-to-invoke-operation-after-successful-login","errorCode":null,"errorMessage":"Unable to invoke operation after successful login","messagePattern":"Unable to invoke operation after successful login","errorType":"exception","errorClass":"LoginSuccessReinvokeException","httpStatus":null,"severity":"error","filePath":"plugins/repositories/core/src/main/java/org/pentaho/di/ui/repo/timeout/SessionTimeoutHandler.java","lineNumber":169,"sourceCode":"      }\n    }\n    return null;\n  }\n\n  /**\n   * Called after the user successfully logs in. Initializes repository providers and\n   * re-invokes the original method.\n   */\n  private Object handleLoginSuccess( Object objectToHandle, Method method, Object[] args )\n      throws LoginSuccessReinvokeException {\n    initializeRepositoryProvidersAfterReconnection( getSpoon() );\n    try {\n      return method.invoke( objectToHandle, args );\n    } catch ( InvocationTargetException ex ) {\n      throw new LoginSuccessReinvokeException( \"Failed to re-invoke operation after successful login\",\n          ex.getCause() );\n    } catch ( IllegalAccessException | IllegalArgumentException ex ) {\n      throw new LoginSuccessReinvokeException( \"Unable to invoke operation after successful login\", ex );\n    }\n  }\n\n  static class LoginSuccessReinvokeException extends KettleException {\n    private static final long serialVersionUID = 1L;\n\n    LoginSuccessReinvokeException( String message, Throwable cause ) {\n      super( message, cause );\n    }\n  }\n\n  /**\n   * Wrapper that distinguishes \"reinvocation happened and returned a value (possibly null)\"\n   * from \"no reinvocation was performed\".  Using a plain {@code Object} return would conflate\n   * a legitimate {@code null} return value with \"nothing happened\".\n   */\n  static class ReinvokeResult {\n    private final Object value;","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/repositories/core/src/main/java/org/pentaho/di/ui/repo/timeout/SessionTimeoutHandler.java#L151-L187","documentation":"SessionTimeoutHandler.handleLoginSuccess throws LoginSuccessReinvokeException('Unable to invoke operation after successful login') when the reflective re-invocation after login fails with IllegalAccessException or IllegalArgumentException — the method could not be legally invoked at all (accessibility or argument-type mismatch), independent of any server failure. Like its sibling in RepositorySessionTimeoutHandler, this points to a proxy/signature mismatch bug.","triggerScenarios":"Method is not accessible from the handler, argument types do not match the Method's declaring class, or the receiver object is not an instance of that class after re-login.","commonSituations":"Custom repository implementations with non-public methods; classloader/plugin version mismatch after reconnect; cached Method from a different class version.","solutions":["Make the intercepted methods public and invoke via their declaring class","Re-resolve the Method object from the live instance's class rather than caching it","Verify proxy arguments are not null or of the wrong type before re-invocation"],"exampleFix":"// before\nmethod.invoke( objectToHandle, args ); // IllegalArgumentException if receiver type mismatched\n// after\nif ( !method.getDeclaringClass().isInstance( objectToHandle ) ) {\n  method = objectToHandle.getClass().getMethod( method.getName(), method.getParameterTypes() );\n}\nmethod.invoke( objectToHandle, args );","handlingStrategy":"type-guard","validationCode":"// same invokability check as reflection mismatches\nboolean isInvokable( Object receiver, Method m, Object[] args ) {\n  return Modifier.isPublic( m.getModifiers() )\n      && m.getDeclaringClass().isInstance( receiver )\n      && argsMatch( m.getParameterTypes(), args );\n}","typeGuard":"boolean isInvokable( Object receiver, Method m, Object[] args ) {\n  if ( !m.getDeclaringClass().isInstance( receiver ) ) return false;\n  Class<?>[] pt = m.getParameterTypes();\n  if ( args.length != pt.length ) return false;\n  for ( int i = 0; i < pt.length; i++ ) {\n    if ( args[i] != null && !pt[i].isInstance( args[i] ) ) return false;\n  }\n  return true;\n}","tryCatchPattern":"try {\n  handler.performLoginAndReinvoke( objectToHandle, method, args );\n} catch ( LoginSuccessReinvokeException e ) {\n  if ( e.getCause() instanceof IllegalAccessException\n       || e.getCause() instanceof IllegalArgumentException ) {\n    log.error( \"Reflection invocation bug in timeout handler\", e.getCause() );\n  } else { throw e; }\n}","preventionTips":["Resolve Method handles from the live object's class at invocation time","Ensure argument arrays match the method signature exactly, including nulls","Test session-timeout recovery flows when upgrading repository plugin versions"],"tags":["reflection","login","session"],"backgroundTag":"method-invocation-failed","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"}