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

recordCoverage failed with java.lang.IllegalArgumentException: Cannot merge coverage information

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Minor Minor
    • coverage-model
    • None
    • Jenkins 2.426.3; Coverage Plugin 1.13.0

      java.lang.IllegalArgumentException: Cannot merge coverage information for line 39 in [FILE] DataPlayerWidget.tsx <0>
      	at edu.hm.hafner.coverage.FileNode.mergeCounters(FileNode.java:164)
      	at edu.hm.hafner.coverage.FileNode.mergeNode(FileNode.java:136)
      	at edu.hm.hafner.coverage.Node.lambda$mergeNode$17(Node.java:745)
      	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
      	at edu.hm.hafner.coverage.Node.mergeNode(Node.java:741)
      	at edu.hm.hafner.coverage.Node.lambda$mergeNode$17(Node.java:745)
      	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
      	at edu.hm.hafner.coverage.Node.mergeNode(Node.java:741)
      	at edu.hm.hafner.coverage.Node.merge(Node.java:720)
      	at java.base/java.util.stream.ReduceOps$2ReducingSink.accept(ReduceOps.java:123)
      	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
      	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
      	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
      	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
      	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
      	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
      	at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:558)
      	at edu.hm.hafner.coverage.Node.merge(Node.java:687)
      	at io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.aggregateResults(CoverageRecorder.java:523)
      	at io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.perform(CoverageRecorder.java:413)
      	at io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.perform(CoverageRecorder.java:402)
      	at io.jenkins.plugins.coverage.metrics.steps.CoverageStep$Execution.run(CoverageStep.java:365)
      	at io.jenkins.plugins.coverage.metrics.steps.CoverageStep$Execution.run(CoverageStep.java:333)
      	at org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution.lambda$start$0(SynchronousNonBlockingStepExecution.java:47)
      	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
      	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
      	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
      	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
      	at java.base/java.lang.Thread.run(Thread.java:829)
      

      This build is running both Jest and Cypress tests. Coverage results are originally created in Istanbul's JSON format, then converted to Cobertura using nyc. The number of branches for condition-coverage attributes can differ between the two, and Coverage Plugin is failing to merge them.

      Heavily truncated, output from nyc looks like

      Jest:

      <coverage lines-valid="34206" lines-covered="26794" line-rate="0.7833" branches-valid="13748" branches-covered="9773" branch-rate="0.7108" timestamp="1710203429645" complexity="0" version="0.1">
        <sources>
          <source>
            /var/lib/jenkins/workspace/feature_DMAS-79190-cypress-split
          </source>
        </sources>
        <packages>
          ...
          <package name="domain.AppComponents.Dashboard" line-rate="0.9664" branch-rate="0.8937">
            ...
            <class name="DataPlayerWidget.tsx" filename="src/domain/AppComponents/Dashboard/DataPlayerWidget.tsx" line-rate="0.25" branch-rate="0">
              <methods>
                <method name="(anonymous_0)" hits="0" signature="()V">
                  <lines>
                    <line number="25" hits="0"/>
                  </lines>
                </method>
              </methods>
              <lines>
                <line number="25" hits="5" branch="false"/>
                <line number="39" hits="0" branch="true" condition-coverage="0% (0/2)"/>
                <line number="40" hits="0" branch="false"/>
                <line number="53" hits="0" branch="false"/>
              </lines>
            </class>
            ...
          </package>
          ...
        </packages>
      </coverage>
      

      Cypress:

      <coverage lines-valid="16792" lines-covered="9482" line-rate="0.5646" branches-valid="6512" branches-covered="2888" branch-rate="0.4434" timestamp="1710205408329" complexity="0" version="0.1">
        <sources>
          <source>
            /var/lib/jenkins/workspace/feature_DMAS-79190-cypress-split
          </source>
        </sources>
        <packages>
          ...
          <package name="domain.AppComponents.Dashboard" line-rate="0.5257000000000001" branch-rate="0.4964">
            <classes>
              ...
              <class name="DataPlayerWidget.tsx" filename="src/domain/AppComponents/Dashboard/DataPlayerWidget.tsx" line-rate="0.25" branch-rate="0">
                <methods>
                  <method name="(anonymous_0)" hits="0" signature="()V">
                    <lines>
                      <line number="25" hits="0"/>
                    </lines>
                  </method>
                </methods>
                <lines>
                  <line number="25" hits="5" branch="false"/>
                  <line number="39" hits="0" branch="true" condition-coverage="0% (0/1)"/>
                  <line number="40" hits="0" branch="false"/>
                  <line number="53" hits="0" branch="false"/>
                </lines>
              </class>
              ...
            </classes>
            ...
          </package>
        </packages>
      </coverage>
      

      It goes without saying that nyc's output is incorrect, but that tool hasn't had a commit since 2020 and I don't have much expectation that they're going to fix the issue. It would be valuable for us if Coverage Plugin could perform a best guess merge of invalid results instead of failing.

      For now, we've switched back to the deprecated Cobertura Plugin, which is able to merge the two files.

          [JENKINS-72895] recordCoverage failed with java.lang.IllegalArgumentException: Cannot merge coverage information

          Ulli Hafner added a comment -

          Could perform a best guess merge of invalid results instead of failing.

          For now, we've switched back to the deprecated Cobertura Plugin, which is able to merge the two files.

          Which branch coverage does Cobertura report? Or what result would make sense in general? Use the value with the higher number of branches?

          Ulli Hafner added a comment - Could perform a best guess merge of invalid results instead of failing. For now, we've switched back to the deprecated Cobertura Plugin, which is able to merge the two files. Which branch coverage does Cobertura report? Or what result would make sense in general? Use the value with the higher number of branches?

          Cobertura doesn't have access to the source code right now, so I can't easily see how it shows that line in the report. I'll try to add it.

          Using the value with the higher number of branches feels appropriate to me.

          Patrick Conley added a comment - Cobertura doesn't have access to the source code right now, so I can't easily see how it shows that line in the report. I'll try to add it. Using the value with the higher number of branches feels appropriate to me.

          In a surprising turn of events, the Cobertura plugin displays the branch coverage with the smaller total:

          I suspect that in the absence of obviously-good coverage data, it displays results from the first file it processed - our cypress results come first, alphabetically.

          (different line numbers are because this screenshot is from a different source file; the XML is effectively the same as in the description)

          Patrick Conley added a comment - In a surprising turn of events, the Cobertura plugin displays the branch coverage with the smaller total: I suspect that in the absence of obviously-good coverage data, it displays results from the first file it processed - our cypress results come first, alphabetically. (different line numbers are because this screenshot is from a different source file; the XML is effectively the same as in the description)

          Ulli Hafner added a comment -

          I'm not sure if I missed something but that should be fixed with the latest parser?

          Ulli Hafner added a comment - I'm not sure if I missed something but that should be fixed with the latest parser?

          Patrick Conley added a comment - - edited

          This isn't fixed, I'm afraid. My latest attempt had the same error

          Found unhandled java.lang.IllegalArgumentException exception:
          
          Cannot merge coverage information for line 79 in [FILE] ShareAdvanced.jsx <0>
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.FileNode.mergeCounters(FileNode.java:199)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.FileNode.mergeNode(FileNode.java:165)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.Node.lambda$mergeNode$13(Node.java:769)
          	java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.Node.mergeNode(Node.java:765)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.Node.lambda$mergeNode$13(Node.java:769)
          	java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.Node.mergeNode(Node.java:765)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.Node.merge(Node.java:744)
          	java.base/java.util.stream.ReduceOps$2ReducingSink.accept(ReduceOps.java:123)
          	java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
          	java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
          	java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
          	java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
          	java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
          	java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
          	java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:662)
          	PluginClassLoader for coverage//edu.hm.hafner.coverage.Node.merge(Node.java:711)
          	PluginClassLoader for coverage//io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.aggregateResults(CoverageRecorder.java:547)
          	PluginClassLoader for coverage//io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.perform(CoverageRecorder.java:417)
          	PluginClassLoader for coverage//io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.perform(CoverageRecorder.java:406)
          	PluginClassLoader for coverage//io.jenkins.plugins.coverage.metrics.steps.CoverageStep$Execution.run(CoverageStep.java:365)
          	PluginClassLoader for coverage//io.jenkins.plugins.coverage.metrics.steps.CoverageStep$Execution.run(CoverageStep.java:333)
          	PluginClassLoader for workflow-step-api//org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution.lambda$start$0(SynchronousNonBlockingStepExecution.java:47)
          	java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
          	java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
          	java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
          	java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
          	java.base/java.lang.Thread.run(Thread.java:833)
          

          on the line

          <line number="79" hits="0" branch="true" condition-coverage="0% (0/3)"/>
          

          vs

          <line number="79" hits="0" branch="true" condition-coverage="0% (0/4)"/>
          

          Patrick Conley added a comment - - edited This isn't fixed, I'm afraid. My latest attempt had the same error Found unhandled java.lang.IllegalArgumentException exception: Cannot merge coverage information for line 79 in [FILE] ShareAdvanced.jsx <0> PluginClassLoader for coverage //edu.hm.hafner.coverage.FileNode.mergeCounters(FileNode.java:199) PluginClassLoader for coverage //edu.hm.hafner.coverage.FileNode.mergeNode(FileNode.java:165) PluginClassLoader for coverage //edu.hm.hafner.coverage.Node.lambda$mergeNode$13(Node.java:769) java.base/java.util.ArrayList.forEach(ArrayList.java:1511) PluginClassLoader for coverage //edu.hm.hafner.coverage.Node.mergeNode(Node.java:765) PluginClassLoader for coverage //edu.hm.hafner.coverage.Node.lambda$mergeNode$13(Node.java:769) java.base/java.util.ArrayList.forEach(ArrayList.java:1511) PluginClassLoader for coverage //edu.hm.hafner.coverage.Node.mergeNode(Node.java:765) PluginClassLoader for coverage //edu.hm.hafner.coverage.Node.merge(Node.java:744) java.base/java.util.stream.ReduceOps$2ReducingSink.accept(ReduceOps.java:123) java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:662) PluginClassLoader for coverage //edu.hm.hafner.coverage.Node.merge(Node.java:711) PluginClassLoader for coverage //io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.aggregateResults(CoverageRecorder.java:547) PluginClassLoader for coverage //io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.perform(CoverageRecorder.java:417) PluginClassLoader for coverage //io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.perform(CoverageRecorder.java:406) PluginClassLoader for coverage //io.jenkins.plugins.coverage.metrics.steps.CoverageStep$Execution.run(CoverageStep.java:365) PluginClassLoader for coverage //io.jenkins.plugins.coverage.metrics.steps.CoverageStep$Execution.run(CoverageStep.java:333) PluginClassLoader for workflow-step-api //org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution.lambda$start$0(SynchronousNonBlockingStepExecution.java:47) java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) java.base/java.lang. Thread .run( Thread .java:833) on the line <line number= "79" hits= "0" branch= "true" condition-coverage= "0% (0/3)" /> vs <line number= "79" hits= "0" branch= "true" condition-coverage= "0% (0/4)" />

          Ulli Hafner added a comment -

          Obviously, I cannot merge these two files: in one report we count 3 branches, in the other one we count 4 branches. It makes sense to dig into the tools that create the reports why they produce inconsistent results.

          Ulli Hafner added a comment - Obviously, I cannot merge these two files: in one report we count 3 branches, in the other one we count 4 branches. It makes sense to dig into the tools that create the reports why they produce inconsistent results.

          This seems to be a bug in the tool, nyc, but it hasn't been maintained in years.

          I'm able to display the Jest & Cypress results separately, but it would be valuable to be able to combine them like we could with the Cobertura plugin.

          Patrick Conley added a comment - This seems to be a bug in the tool, nyc, but it hasn't been maintained in years. I'm able to display the Jest & Cypress results separately, but it would be valuable to be able to combine them like we could with the Cobertura plugin.

          Ulli Hafner added a comment -

          Maybe it makes sense to choose the maximum if the ignore-error property is set.

          Ulli Hafner added a comment - Maybe it makes sense to choose the maximum if the ignore-error property is set.

            drulli Ulli Hafner
            pconley Patrick Conley
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: