pentaho/pentaho-kettle · error · LoginSuccessReinvokeException
Unable to invoke operation after successful login
Error message
Unable to invoke operation after successful login
What it means
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.
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
Example fix
// before
method.invoke( objectToHandle, args ); // IllegalArgumentException if receiver type mismatched
// after
if ( !method.getDeclaringClass().isInstance( objectToHandle ) ) {
method = objectToHandle.getClass().getMethod( method.getName(), method.getParameterTypes() );
}
method.invoke( objectToHandle, args ); Defensive patterns
Strategy: type-guard
Validate before calling
// same invokability check as reflection mismatches
boolean isInvokable( Object receiver, Method m, Object[] args ) {
return Modifier.isPublic( m.getModifiers() )
&& m.getDeclaringClass().isInstance( receiver )
&& argsMatch( m.getParameterTypes(), args );
} Type guard
boolean isInvokable( Object receiver, Method m, Object[] args ) {
if ( !m.getDeclaringClass().isInstance( receiver ) ) return false;
Class<?>[] pt = m.getParameterTypes();
if ( args.length != pt.length ) return false;
for ( int i = 0; i < pt.length; i++ ) {
if ( args[i] != null && !pt[i].isInstance( args[i] ) ) return false;
}
return true;
} Try / catch
try {
handler.performLoginAndReinvoke( objectToHandle, method, args );
} catch ( LoginSuccessReinvokeException e ) {
if ( e.getCause() instanceof IllegalAccessException
|| e.getCause() instanceof IllegalArgumentException ) {
log.error( "Reflection invocation bug in timeout handler", e.getCause() );
} else { throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Custom repository implementations with non-public methods; classloader/plugin version mismatch after reconnect; cached Method from a different class version.
Related errors
- Failed to re-invoke operation after successful login
- Failed to retry repository operation after reconnect
- Unable to invoke repository operation after reconnect
- Attempting to create PDI Repository with no Active…
- Browser session authentication requested but no JSESSIONID…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/f531b85828b06026.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/repositories/core/src/main/java/org/pentaho/di/ui/repo/timeout/SessionTimeoutHandler.java:169
}
}
return null;
}
/**
* Called after the user successfully logs in. Initializes repository providers and
* re-invokes the original method.
*/
private Object handleLoginSuccess( Object objectToHandle, Method method, Object[] args )
throws LoginSuccessReinvokeException {
initializeRepositoryProvidersAfterReconnection( getSpoon() );
try {
return method.invoke( objectToHandle, args );
} catch ( InvocationTargetException ex ) {
throw new LoginSuccessReinvokeException( "Failed to re-invoke operation after successful login",
ex.getCause() );
} catch ( IllegalAccessException | IllegalArgumentException ex ) {
throw new LoginSuccessReinvokeException( "Unable to invoke operation after successful login", ex );
}
}
static class LoginSuccessReinvokeException extends KettleException {
private static final long serialVersionUID = 1L;
LoginSuccessReinvokeException( String message, Throwable cause ) {
super( message, cause );
}
}
/**
* Wrapper that distinguishes "reinvocation happened and returned a value (possibly null)"
* from "no reinvocation was performed". Using a plain {@code Object} return would conflate
* a legitimate {@code null} return value with "nothing happened".
*/
static class ReinvokeResult {
private final Object value;View on GitHub (pinned to f3058517a1)