Skip to content

[JENKINS-49601] Fix NPE in ReplayCause when replaying Runs. fixes #1401#1729

Open
rbrindl wants to merge 4 commits intojenkinsci:masterfrom
rbrindl:fix_NPE_in_ReplayCause
Open

[JENKINS-49601] Fix NPE in ReplayCause when replaying Runs. fixes #1401#1729
rbrindl wants to merge 4 commits intojenkinsci:masterfrom
rbrindl:fix_NPE_in_ReplayCause

Conversation

@rbrindl
Copy link

@rbrindl rbrindl commented Jan 14, 2026

Fixes #1401. [edited by jglick to follow normal linking style]
The fix checks the member variable run and run.getParent() for null and returns null in that case
Otherwise it calls getBuildNumber() on the parent, as in the original code.

Testing done

Two unit tests that demonstrate both failure modes

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests that demonstrate the feature works or the issue is fixed

@rbrindl rbrindl requested a review from a team as a code owner January 14, 2026 12:37
@rbrindl rbrindl changed the title [JENKINS-49601] Fix NPE in ReplayCause when replaying Runs. [JENKINS-49601] Fix NPE in ReplayCause when replaying Runs. fixes #1401 Jan 14, 2026
Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR does not break anything exactly, but it is not really solving the problem, whatever that is. Is onAddedTo / onLoad not getting called for some reason? Or getting called, but after some other code is using the cause? The tests here are not helpful since they do not correspond to a real user scenario reproducing the NPE.

Comment on lines +28 to +34
// construct cause, don't call onAddedTo yet.
ReplayCause cause = new ReplayCause(original);
assertNull(cause.getRun());

// verify print() does not throw NPE.
TaskListener listener = StreamTaskListener.fromStdout();
cause.print(listener);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is meaningless; it does not correspond to a real scenario. A cause should not be used until it is attached to something.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not say its meaningless, because this is exactly what happens on our Jenkins instances about every two weeks when someone replays a job. So it IS a real scenario: there is a ReplayCause with a run that is null, and that's exactly what these tests check. I don't know (or can only speculate) why this is.
But since the constructor of ReplayCause does not set run, but only onLoad() and onAddedTo() do, there definitely is a window of opportunity in which run is null.
The same goes for the de-serialization case.
I didn't want to make this more complicated than necessary: There is a member that may be null when dereferenced, so a null-check seems to be in order. I can drop the tests, if you like.

Comment on lines +53 to +60
// serialize and deserialize the cause, which should clear the transient run field.
XStream2 xs = new XStream2();
String xml = xs.toXML(cause);

Object obj = xs.fromXML(xml);
if (obj instanceof ReplayCause) {
ReplayCause deserialized = (ReplayCause) obj;
assertNull(deserialized.getRun());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JENKINS-49601] Triggering downstream pipeline from a replayed one ends in a NullPointerException

2 participants