Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-59778

Pipeline script fails to call Java code on slave: Failed to deserialize the Callable object

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Minor
    • Resolution: Won't Fix
    • Component/s: pipeline, remoting
    • Labels:
      None
    • Environment:
      Jenkins server: 2.190.1
    • Similar Issues:

      Description

      This is a simple pipeline script on which the issue is reproduced:

      import jenkins.security.MasterToSlaveCallable;
      //import hudson.remoting.Callable;
      
      def executeJavaCodeOnNode() {
      
          def node = Jenkins.getInstance().slaves.find({it.name == env.NODE_NAME})
          def hostChannel = node.getComputer().getChannel()
          def task = new MasterToSlaveCallable<String, IOException>() {
                  public String call() throws IOException {
                      return new String("-on the node-");
                  }
          };
              
          hostChannel.call(task);
      }
      
      // Main
      node ('linux-01') {
          executeJavaCodeOnNode()
      }
      

      This simple pipeline script fails with multiple Java exceptions. I think the most relevent of them are:

      java.lang.IllegalArgumentException: Unable to locate class file for class WorkflowScript$1
      	at hudson.remoting.Which.classFileUrl(Which.java:65)
      	at hudson.remoting.RemoteClassLoader$ClassLoaderProxy.fetch4(RemoteClassLoader.java:860)
      	at hudson.remoting.RemoteClassLoader$ClassLoaderProxy.fetch3(RemoteClassLoader.java:889)
      	at sun.reflect.GeneratedMethodAccessor753.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at hudson.remoting.RemoteInvocationHandler$RPCRequest.perform(RemoteInvocationHandler.java:929)
      	at hudson.remoting.Request$2.run(Request.java:369)
      	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
      	at org.jenkinsci.remoting.CallableDecorator.call(CallableDecorator.java:19)
      	at hudson.remoting.CallableDecoratorList$1.call(CallableDecoratorList.java:21)
      	at jenkins.util.ContextResettingExecutorService$2.call(ContextResettingExecutorService.java:46)
      	at jenkins.security.ImpersonatingExecutorService$2.call(ImpersonatingExecutorService.java:71)
      

      and

      Also:   hudson.remoting.Channel$CallSiteStackTrace: Remote call to channel
      		at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1743)
      		at hudson.remoting.Request.call(Request.java:202)
      		at hudson.remoting.RemoteInvocationHandler.invoke(RemoteInvocationHandler.java:286)
      		at com.sun.proxy.$Proxy5.fetch3(Unknown Source)
      		at hudson.remoting.RemoteClassLoader.findClass(RemoteClassLoader.java:209)
      		at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
      		at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
      		at java.lang.Class.forName0(Native Method)
      		at java.lang.Class.forName(Class.java:348)
      		at hudson.remoting.MultiClassLoaderSerializer$Input.resolveClass(MultiClassLoaderSerializer.java:134)
      		at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1868)
      		at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
      		at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
      		at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
      		at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
      		at hudson.remoting.UserRequest.deserialize(UserRequest.java:291)
      		at hudson.remoting.UserRequest.perform(UserRequest.java:190)
      		at hudson.remoting.UserRequest.perform(UserRequest.java:54)
      		at hudson.remoting.Request$2.run(Request.java:369)
      		at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
      ....
      ....
      ....
      Caused: java.lang.Error: Failed to deserialize the Callable object.
      	at hudson.remoting.UserRequest.perform(UserRequest.java:196)
      	at hudson.remoting.UserRequest.perform(UserRequest.java:54)
      	at hudson.remoting.Request$2.run(Request.java:369)
      	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
      

      I thought that this issue is connected to serialization and tried to add @NonCPS to my method, but it did not help.

        Attachments

          Activity

          Hide
          danielbeck Daniel Beck added a comment -

          I'm pretty sure writing callables in pipeline is unsupported.

          Devin Nusbaum perhaps? Does this look sane?

          Show
          danielbeck Daniel Beck added a comment - I'm pretty sure writing callables in pipeline is unsupported. Devin Nusbaum perhaps? Does this look sane?
          Hide
          dnusbaum Devin Nusbaum added a comment -

          Yes, using remoting directly from Pipelines is not supported. The supported way to do this from Pipeline is to implement Step in a plugin, and have the step handle the interactions with remoting. Alexander Samoylov, this has never worked for you, right? Or did it work previously before some plugin/core upgrade?

          Show
          dnusbaum Devin Nusbaum added a comment - Yes, using remoting directly from Pipelines is not supported. The supported way to do this from Pipeline is to implement Step in a plugin, and have the step handle the interactions with remoting. Alexander Samoylov , this has never worked for you, right? Or did it work previously before some plugin/core upgrade?
          Hide
          alexander_samoylov Alexander Samoylov added a comment - - edited

          Devin Nusbaum, Yes, it never worked for me. I will try to describe my use case better.
          I ran some Java code on slave for debugging purposes. I used the class GroovyInstallation in my pipeline script and the problem was the getExecutable(VirtualChannel channel) method of this class returned null (even after the successful installation).
          The method getExecutable(VirtualChannel channel) does almost the same what I wrote in my example above (see https://github.com/jenkinsci/groovy-plugin/blob/master/src/main/java/hudson/plugins/groovy/GroovyInstallation.java), that is uses Callable. I wanted to do the same directly from the pipeline code in order to run my modified version of getExecutable (with printouts etc.), but as you see it failed with those exceptions.

          Obviously I had a question, why Callable usage works via the instance of GroovyInstallation, but does not work from the pipeline directly. I didn't understand what is actually the difference and that's why opened this ticket. If you think that this is not supported, why then it works fine via the instance of GroovyInstallation?

          Show
          alexander_samoylov Alexander Samoylov added a comment - - edited Devin Nusbaum , Yes, it never worked for me. I will try to describe my use case better. I ran some Java code on slave for debugging purposes. I used the class GroovyInstallation in my pipeline script and the problem was the getExecutable(VirtualChannel channel) method of this class returned null (even after the successful installation). The method getExecutable(VirtualChannel channel) does almost the same what I wrote in my example above (see https://github.com/jenkinsci/groovy-plugin/blob/master/src/main/java/hudson/plugins/groovy/GroovyInstallation.java ), that is uses Callable. I wanted to do the same directly from the pipeline code in order to run my modified version of getExecutable (with printouts etc.), but as you see it failed with those exceptions. Obviously I had a question, why Callable usage works via the instance of GroovyInstallation, but does not work from the pipeline directly. I didn't understand what is actually the difference and that's why opened this ticket. If you think that this is not supported, why then it works fine via the instance of GroovyInstallation?
          Hide
          dnusbaum Devin Nusbaum added a comment -

          Alexander Samoylov GroovyInstallation is Java code from a plugin. Compared to Groovy code in Pipeline, the most important differences are that it is not CPS-transformed, it is not sandbox-transformed, its class loader hierarchy is different, and there is a class file on disk for it somewhere instead of whatever happens for Groovy code run by the embedded Groovy interpreter. I suspect the latter is what is causing problems in your case. Both Pipeline Groovy code and remoting do some tricky low-level things, and so they don't play well together.

          If you just want to run some Groovy code for debugging purposes, you could try using the script console, which will at least eliminate the Pipeline-specific complexities, to see if that makes a difference.

          Show
          dnusbaum Devin Nusbaum added a comment - Alexander Samoylov  GroovyInstallation is Java code from a plugin. Compared to Groovy code in Pipeline, the most important differences are that it is not CPS-transformed, it is not sandbox-transformed, its class loader hierarchy is different, and there is a class file on disk for it somewhere instead of whatever happens for Groovy code run by the embedded Groovy interpreter. I suspect the latter is what is causing problems in your case. Both Pipeline Groovy code and remoting do some tricky low-level things, and so they don't play well together. If you just want to run some Groovy code for debugging purposes, you could try using the script console, which will at least eliminate the Pipeline-specific complexities, to see if that makes a difference.
          Hide
          alexander_samoylov Alexander Samoylov added a comment -

          Well, I understand. Thank you for the clarification.
          You wrote also above that "The supported way to do this from Pipeline is to implement Step in a plugin, and have the step handle the interactions with remoting". Probably you know some pipeline code which implements similar thing? I tried to look for on https://github.com/jenkinsci/jenkins-scripts/tree/master/scriptler, but did not find anything useful. Could you please refer to some code snippet, of course if you know such one?

          Show
          alexander_samoylov Alexander Samoylov added a comment - Well, I understand. Thank you for the clarification. You wrote also above that "The supported way to do this from Pipeline is to implement Step in a plugin, and have the step handle the interactions with remoting". Probably you know some pipeline code which implements similar thing? I tried to look for on https://github.com/jenkinsci/jenkins-scripts/tree/master/scriptler , but did not find anything useful. Could you please refer to some code snippet, of course if you know such one?

            People

            • Assignee:
              jthompson Jeff Thompson
              Reporter:
              alexander_samoylov Alexander Samoylov
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: