# Multiple RPC Handlers in Module

**URL:** <https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379>\
**Category:** Module Development\
**Created:** [May 9, 2022, 10:13pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379 "2022-05-09T22:13:26Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![cody.tamaki](https://avatars.discourse-cdn.com/v4/letter/c/b487fb/32.png) [@cody.tamaki](https://forum.inductiveautomation.com/u/cody.tamaki)\
**Post date:** [May 9, 2022, 10:13pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/1 "2022-05-09T22:13:26Z")

</div>

How would I go about adding multiple RPC handlers to the gateway? The current module I’m working on has a fairly large API and I would like to split it over organize it over multiple classes. Do I have to do some sort of switch statement in the `getRPCHandler` class of the GatewayHook? I see that the ModuleRPCFactory allows you to request separate interfaces.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 10, 2022, 6:48am UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/2 "2022-05-10T06:48:34Z")

</div>

You can put your implementations anywhere you want them. The actual RPC implementation returned from the gateway hook can be full of one-liners that delegate to the actual class and method that is appropriate.

The RPC engine does the first “switch” for you with the method name. Nothing prevents you from defining a second level of naming for some of the first level calls.

---

<div class="post-metadata">

**Author:** ![cody.tamaki](https://avatars.discourse-cdn.com/v4/letter/c/b487fb/32.png) [@cody.tamaki](https://forum.inductiveautomation.com/u/cody.tamaki)\
**Post date:** [May 11, 2022, 10:07pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/3 "2022-05-11T22:07:25Z")

</div>

But I’d have to setup a ton of 1 line methods to do this?

So just to clarify what I’m trying to do - I have a bunch of data classes and service classes doing CRUD operations on the gateway representing some objects in my module and I was hoping I could make a abstract RPC handler like this:

```auto
public abstract class RpcHandler<T> {}...

```

Then I’d like to find a way to have a top level RPC handler class return a reference to that so I can save myself from having to write 1000’s of one liners delegating everything to the correct member service method.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [May 11, 2022, 10:33pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/4 "2022-05-11T22:33:58Z")

</div>

I think the best you’re going to get is the “delegate” pattern.

Imagine you have interfaces `IFoo` and `IBar`, and class `ModuleRPC`.

Implement `ModuleRPC` like this:

```auto
public class ModuleRPC implements IFoo, IBar {

    IFoo fooImpl;
    IBar barImpl;

    @Override
    public void bar() {
        barImpl.bar();
    }

    @Override
    public void foo() {
        fooImpl.foo();
    }

}

```

but let IntelliJ generate all the delegated methods for you once you’ve added the impl references via `Code > Generate... > Delegate Methods...`.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 11, 2022, 11:12pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/5 "2022-05-11T23:12:53Z")

</div>

And if you’re allergic to boilerplate, “just” switch to Kotlin 😉

```auto
class ModuleRPC(context: GatewayContext) : IFoo by FooImpl(context), IBar by BarImpl(context)

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 12, 2022, 12:39pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/6 "2022-05-12T12:39:03Z")

</div>

> [@pturmel](#):
>
> Nothing prevents you from defining a second level of naming for some of the first level calls.

Strictly speaking, the RPC system just does switching on string identifiers. First is the module ID, where Ignition looks up the module to get your handler. It then looks up the method name (second string identifier) via reflection and hands off the rest of the arguments to that method.

Nothing prevents you from setting up another layer of indirection, into classes of your choice. Or some mixture, where some methods do further indirection and some perform a direct action.

You don't even have to make interfaces for everything if you simply define methods that accept `Object...` variants.

---

<div class="post-metadata">

**Author:** ![cody.tamaki](https://avatars.discourse-cdn.com/v4/letter/c/b487fb/32.png) [@cody.tamaki](https://forum.inductiveautomation.com/u/cody.tamaki)\
**Post date:** [May 12, 2022, 2:22pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/7 "2022-05-12T14:22:05Z")

</div>

This is what I ended up doing actually. I thought I’d post the solution here if anybody is looking for the same thing here in the future.

I made a hash-map of the various RPC service I would like to be exposed then defined a single method in my gateway RPC handler:

```auto
    @Override
    public <T> T invoke(Class<?> apiClass, String method, Object... args) {
        var service = serviceMap.get(apiClass);
        Objects.requireNonNull(service, "No service found for class " + apiClass);
        try {
            return ReflectionUtils.invokeMethod(service, method, args);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

```

Then added a method to a reflections utility class to call the method I want:

```auto
    @SuppressWarnings("unchecked")
    public static <T> T invokeMethod(Object bean, String methodName, Object... args) throws IllegalAccessException, 
            InvocationTargetException, NoSuchMethodException {
        
        Class<?> beanClass = bean.getClass();
        Class<?>[] argTypes = new Class<?>[args.length];
        for (int i = 0; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }

        Method method = beanClass.getMethod(methodName, argTypes);
        
        return (T) method.invoke(bean, args);
    }

```

I quite liked having a common interface so that I have to fulfill a contract on both ends of the RPC call because I think that will prevent a lot of bugs…

---

<div class="post-metadata">

**Author:** ![e.sagnelonge](https://avatars.discourse-cdn.com/v4/letter/e/7cd45c/32.png) [@e.sagnelonge](https://forum.inductiveautomation.com/u/e.sagnelonge)\
**Post date:** [November 29, 2023, 2:05pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/8 "2023-11-29T14:05:36Z")

</div>

Hello @cody.tamaki,

I'm trying to reproduce the same RPC Handler as you.  
But I don't understand how you override the invoke method.

Does your RPC Handler extends/implements from another class?

---

<div class="post-metadata">

**Author:** ![Mathias\_Melling](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mathias_melling/32/67682_2.png) [@Mathias\_Melling](https://forum.inductiveautomation.com/u/Mathias_Melling)\
**Post date:** [May 2, 2024, 3:57pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/9 "2024-05-02T15:57:51Z")

</div>

I'm also trying to use multiple RPC Handlers, but can't figure it out even after reading through this Post a hundred times.

Here is what I've got so far.  
In the Common scope:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/d/9dd8d3c1fc0344ff2e58453e1b4e3d9ed7438789.png)

In the Gateway scope:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/9/e96964308b84a9d08efe963e8a87ebb4a0e4a650.png)

In the Client Scope:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/8/18109f9cd70db22f5f89e06c4c21f802daf1fbb3.png)

Under ClientTagHandler I want to have a rpc call that calls the methods defined under GatewayTagHandler. And under ClientLV\_Scripts I want to have a rpc call that calls the methods defined under GatewayLV\_Scripts.

What do I need to do to make this work?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 2, 2024, 3:58pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/10 "2024-05-02T15:58:37Z")

</div>

You can't. A module can only have one RPC handler.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 2, 2024, 4:00pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/11 "2024-05-02T16:00:17Z")

</div>

Good news: You will be able to have arbitrarily many RPC handlers in 8.3, under custom "namespaces" within your module.

---

<div class="post-metadata">

**Author:** ![Mathias\_Melling](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mathias_melling/32/67682_2.png) [@Mathias\_Melling](https://forum.inductiveautomation.com/u/Mathias_Melling)\
**Post date:** [May 2, 2024, 4:02pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/12 "2024-05-02T16:02:29Z")

</div>

Any word on when 8.3 is coming out?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 2, 2024, 4:05pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/13 "2024-05-02T16:05:12Z")

</div>

No earlier than the end of this year.

A beta release _may_ be available _around_ ICC, in September.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [May 2, 2024, 5:26pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/14 "2024-05-02T17:26:23Z")

</div>

Are there still plans to provide early access for module authors once API changes are finalized?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [May 2, 2024, 5:27pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/15 "2024-05-02T17:27:00Z")

</div>

The beta will be the early access for most developers.

---

<div class="post-metadata">

**Author:** ![Mathias\_Melling](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mathias_melling/32/67682_2.png) [@Mathias\_Melling](https://forum.inductiveautomation.com/u/Mathias_Melling)\
**Post date:** [May 2, 2024, 9:02pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/16 "2024-05-02T21:02:56Z")

</div>

Here is what I've done now.  
GatewayHook:

```python
@Override
public Object getRPCHandler(ClientReqSession session, String projectName) {
    
    return new RPCHandler();
}

```

RPCHandler:

```python
public class RPCHandler implements RPCHandlerIntf {
    
    @Override
    public TagHandler getTagHandler(){
        return new GatewayTagHandler();
    }
    
    @Override
    public ScriptInterface getScripts(){
        return new GatewayScripts();
    }
    
    @Override
    public double square(double value){
        return value*value;
    }
}

```

RPCHandlerIntf:

```python
public interface RPCHandlerIntf {
    
    public TagHandler getTagHandler();
    
    public ScriptInterface getScripts();
    
    public double square(double value);
}

```

ClientScripts:

```python
public class ClientScripts extends AbstractScripts {
    
    public static RPCHandlerIntf rpc = ModuleRPCFactory.create(
            "com.lvcontrol.ignition",
            RPCHandlerIntf.class);
    
    public ClientScripts(){
        
    }
    
    @Override
    public double multiply(double val1, double val2) {
        return rpc.getScripts().multiply(val1, val2);
    }
    
    public double square(double value){
        return rpc.square(value);
    }
}

```

ClientHook:

```python
public void initializeScriptManager(ScriptManager manager) {
        super.initializeScriptManager(manager);

        manager.addScriptModule("system.lvcontrol",
            new ClientScripts(),
            new PropertiesFileDocProvider()
        );
    }

```

The `square(value)` script works, but the `multiply(val1,val2)` script doesn't.

---

<div class="post-metadata">

**Author:** ![Mathias\_Melling](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mathias_melling/32/67682_2.png) [@Mathias\_Melling](https://forum.inductiveautomation.com/u/Mathias_Melling)\
**Post date:** [May 2, 2024, 9:18pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/17 "2024-05-02T21:18:26Z")

</div>

The `multiply` script throws the following, anyone know why?

```python
>>> 
Java Traceback:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
	at jdk.proxy2/jdk.proxy2.$Proxy51.getScripts(Unknown Source)
	at com.lvcontrol.ignition.scripting.ClientScripts.multiply(ClientScripts.java:28)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.lang.reflect.UndeclaredThrowableException: java.lang.reflect.UndeclaredThrowableException
	at org.python.core.Py.JavaError(Py.java:545)
	at org.python.core.Py.JavaError(Py.java:536)
	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:192)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction. __call__ (ScriptManager.java:553)
	at org.python.core.PyObject. __call__ (PyObject.java:477)
	at org.python.core.PyObject. __call__ (PyObject.java:481)
	at org.python.pycode._pyx10.f$0(<input>:1)
	at org.python.pycode._pyx10.call_function(<input>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1703)
	at org.python.core.Py.exec(Py.java:1747)
	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:277)
	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:130)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:628)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:616)
	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.UndeclaredThrowableException
	at jdk.proxy2/jdk.proxy2.$Proxy51.getScripts(Unknown Source)
	at com.lvcontrol.ignition.scripting.ClientScripts.multiply(ClientScripts.java:28)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:190)
	... 19 more
Caused by: com.inductiveautomation.ignition.client.gateway_interface.GatewayException: class com.lvcontrol.ignition.scripting.GatewayScripts cannot be cast to class java.io.Serializable (com.lvcontrol.ignition.scripting.GatewayScripts is in unnamed module of loader com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader @430e86c0; java.io.Serializable is in module java.base of loader 'bootstrap')
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.newGatewayException(GatewayInterface.java:360)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:334)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:287)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.moduleInvokeSafe(GatewayInterface.java:930)
	at com.inductiveautomation.ignition.client.gateway_interface.ModuleRPCFactory$DynamicRPCHandler.invoke(ModuleRPCFactory.java:53)
	... 26 more
Caused by: java.lang.ClassCastException: class com.lvcontrol.ignition.scripting.GatewayScripts cannot be cast to class java.io.Serializable (com.lvcontrol.ignition.scripting.GatewayScripts is in unnamed module of loader com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader @430e86c0; java.io.Serializable is in module java.base of loader 'bootstrap')
	at com.inductiveautomation.ignition.gateway.servlets.gateway.functions.ModuleInvoke.invoke(ModuleInvoke.java:172)
	at com.inductiveautomation.ignition.gateway.servlets.Gateway.doPost(Gateway.java:435)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:523)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
	at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:86)
	at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1410)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:764)
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1665)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:527)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1570)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1384)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:484)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1543)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1306)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at com.inductiveautomation.catapult.handlers.RemoteHostNameLookupHandler.handle(RemoteHostNameLookupHandler.java:121)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:301)
	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:51)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:141)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.server.Server.handle(Server.java:563)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$0(HttpChannel.java:505)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:762)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:497)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:282)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:314)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:416)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:385)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:272)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.lambda$new$0(AdaptiveExecutionStrategy.java:140)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:411)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
	at java.lang.Thread.run(null)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
	at jdk.proxy2/jdk.proxy2.$Proxy51.getScripts(Unknown Source)
	at com.lvcontrol.ignition.scripting.ClientScripts.multiply(ClientScripts.java:28)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.lang.reflect.UndeclaredThrowableException: java.lang.reflect.UndeclaredThrowableException
>>> 

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 2, 2024, 9:20pm UTC](https://forum.inductiveautomation.com/t/multiple-rpc-handlers-in-module/59379/18 "2024-05-02T21:20:28Z")

</div>

> [@Mathias\_Melling](#):
>
> `Caused by: java.lang.ClassCastException: class com.lvcontrol.ignition.scripting.GatewayScripts cannot be cast to class java.io.Serializable`

The RPC proxy stuff is trying to return an instance of your `GatewayScripts` class to the client, because of this line in `ClientScripts`:  
`rpc.getScripts().multiply(val1, val2)`
