Phoenix
Phoenix

Reputation: 105

Jenkins pipeline "java.io.NotSerializableException: hudson.model.User" when execute shell

Here is my pipeline code. Notice the function promoteBuild() is a fake one, it needs to execute shell blocks. Here I just let it echo a constant string.

   pipeline {
    agent none

    stages {
        stage("PromoteBuild") {
            agent {
                label "test_agent"
            }
            steps {

                script {

                    mopName = "mop name"
                    try {

                        // Timeout in case to avoid running this forever
                        timeout(time: 30, unit: 'SECONDS') {
                            promoteMap = input id: 'promote', message: 'Choose bundled buildNumbers', ok: 'Promote?',
                                    parameters: [

                                            string(
                                                    defaultValue: mopName,
                                                    description: '',
                                                    name: 'MopName'),

                                    ],
                                    submitter: "xxxx", submitterParameter: 'approver'
                        }
                      promoteBuild()

                    } catch (err) {
                        def user = err.getCauses()[0].getUser()
                        if ('SYSTEM' == user.toString()) { // SYSTEM means timeout.
                            //No response means the build is launched by timer, promote the first bundled-number
                            echo "Promote only. No following deployment"
                            promoteBuild()
                            currentBuild.result = 'SUCCESS'
                        } else {
                            //if user aborted this operation, do nothing and mark the build as aborted
                            currentBuild.result = 'ABORTED'

                            echo "This build was aborted by [${user}]"
                        }

                    }

                }
            }
        }
    }

def promoteBuild() {
sh """
    echo "hello"
  """
}

The function promoteBuild works successfully in try block (when I respond to the input request) but fails in catch block (when it is timeout).

Below is the console output:

Input requested
Cancelling nested steps due to timeout
[Pipeline] }
[Pipeline] // timeout
[Pipeline] echo
Promote only. No following deployment
[Pipeline] sh
[testTmp] Running shell script
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
***java.io.NotSerializableException: hudson.model.User***
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
    at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
    at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
    at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
    at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
    at java.util.HashMap.internalWriteEntries(HashMap.java:1777)
    at java.util.HashMap.writeObject(HashMap.java:1354)
    at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
    at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
    at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
    at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
    at java.util.TreeMap.writeObject(TreeMap.java:2434)
    at sun.reflect.GeneratedMethodAccessor421.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)

I'm pretty sure it is not related with "User" because the build succeeded if I remove the shell invoking. Any hint?

Upvotes: 3

Views: 6123

Answers (2)

California Sober
California Sober

Reputation: 43

@Vasan's answer is the right solution. I just want to add why the behavior is different when you don't add the line promoteBuild() or you remove the shell invoke. As stated in the doc,

Since pipelines must survive Jenkins restarts, the state of the running program is periodically saved to disk so it can be resumed later (saves occur after every step or in the middle of steps such as sh).

you can see that the step with sh invoking will trigger the pipeline state to be saved, and hence the serializing action, which then causes the java.io.NotSerializableException to be thrown.

Upvotes: 0

Vasan
Vasan

Reputation: 4956

See https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#user-content-serializing-local-variables

As such: any variable values used in your program should be numbers, strings, or other serializable types

Your problem is at this line: def user = err.getCauses()[0].getUser()

The object returned is of type hudson.model.User, which is not serializable i.e. doesn't implement Serializable interface.

Since you're only interested in the user name anyway, you could instead do this:

def user = err.getCauses()[0].getUser().toString()
if ('SYSTEM' == user) {

This will work because String is serializable.

You might also want to find out the real reason for your Exception occurring in the first place - try logging it inside the catch block.

Upvotes: 8

Related Questions