Sonar fails to import Jacoco reports

  • versions used (SonarQube, Scanner, Plugin, and any relevant extension): SonarQube 7.7
  • error observed
java.lang.IllegalStateException: Line 168 is out of range in the file common/src/main/java/app/models/Model.java (lines: 60)
	at org.sonar.api.internal.google.common.base.Preconditions.checkState(Preconditions.java:197)
	at org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage.validateLine(DefaultCoverage.java:93)
	at org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage.lineHits(DefaultCoverage.java:81)
	at org.sonar.plugins.jacoco.ReportImporter.importCoverage(ReportImporter.java:45)
	at org.sonar.plugins.jacoco.JacocoSensor.importReport(JacocoSensor.java:80)
	at org.sonar.plugins.jacoco.JacocoSensor.importReports(JacocoSensor.java:62)
	at org.sonar.plugins.jacoco.JacocoSensor.execute(JacocoSensor.java:46)
	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:48)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:85)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:59)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:77)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:59)
	at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:82)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
	at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:359)
	at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:354)
	at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:351)
	at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:317)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
	at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:128)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
	at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:73)
	at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:67)
	at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
	at com.sun.proxy.$Proxy31.execute(Unknown Source)
	at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:185)
	at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:137)
	at org.sonarsource.scanner.maven.bootstrap.ScannerBootstrapper.execute(ScannerBootstrapper.java:65)
	at org.sonarsource.scanner.maven.SonarQubeMojo.execute(SonarQubeMojo.java:104)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)

We use Javalite framework (http://javalite.io) in our project which modifies bytecode of some Java classes. When I run the maven task

mvn clean install sonar:sonar -Dsonar.host.url=http://localhost:9009 -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml

Jacoco plugin builds the reports just fine, but when sonar is trying to import the report I get the above error. Is there a way to avoid it?

Looks like Jacoco produces invalid report for some reason. According to the error message, in the Jacoco report there is coverage information for file common/src/main/java/app/models/Model.java for line 168, while this file has only 60 lines. If this is indeed the case, you should probably go to Jacoco support to see why your report is wrong.

As I wrote, the framework we use modifies bytecode. So Jacoco reports everything correctly. It’s Sonar which compares Jacoco report with original java file fails.

This explanation does not really fit with the error we are seeing in your post : bytecode can be modified, but line number should not be (unless javalite does generate sources before compilation).
Could you share your XML report ?
Can you shed some light upon how javalite works ? is it modifying compiled classes ? or generating code ?

Javalite does generate sources, but it should not be a problem as Sonar has JaCoCo XML report. Here is a sample (I’ve omitted a couple of methods to save space):

<class name="app/models/CustomField" sourcefilename="CustomField.java">
<method name="&lt;init&gt;" desc="()V" line="67">
	<counter type="INSTRUCTION" missed="0" covered="3"/>
	<counter type="LINE" missed="0" covered="1"/>
	<counter type="COMPLEXITY" missed="0" covered="1"/>
	<counter type="METHOD" missed="0" covered="1"/>
</method>
<method name="&lt;init&gt;" desc="(Lapp/models/User;Ljava/lang/String;Ljava/lang/String;Lapp/models/CustomField$Type;)V" line="69">
	<counter type="INSTRUCTION" missed="0" covered="13"/>
	<counter type="LINE" missed="0" covered="3"/>
	<counter type="COMPLEXITY" missed="0" covered="1"/>
	<counter type="METHOD" missed="0" covered="1"/>
</method>
<method name="findForUser" desc="(Lapp/models/User;)Ljava/util/List;" line="74">
	<counter type="INSTRUCTION" missed="0" covered="4"/>
	<counter type="LINE" missed="0" covered="1"/>
	<counter type="COMPLEXITY" missed="0" covered="1"/>
	<counter type="METHOD" missed="0" covered="1"/>
</method>
<method name="findByContactColumn" desc="(Lapp/models/CustomField$ContactColumn;Lapp/models/User;)Lapp/models/CustomField;" line="78">
	<counter type="INSTRUCTION" missed="0" covered="16"/>
	<counter type="LINE" missed="0" covered="1"/>
	<counter type="COMPLEXITY" missed="0" covered="1"/>
	<counter type="METHOD" missed="0" covered="1"/>
</method>
<method name="findMappedByContactColumnForUser" desc="(Ljava/lang/Long;)Ljava/util/Map;" line="82">
	<counter type="INSTRUCTION" missed="0" covered="27"/>
	<counter type="BRANCH" missed="0" covered="2"/>
	<counter type="LINE" missed="0" covered="6"/>
	<counter type="COMPLEXITY" missed="0" covered="2"/>
	<counter type="METHOD" missed="0" covered="1"/>
</method>
<method name="findForUser" desc="(Ljava/lang/Long;)Ljava/util/List;" line="91">
	<counter type="INSTRUCTION" missed="0" covered="11"/>
	<counter type="LINE" missed="0" covered="1"/>
	<counter type="COMPLEXITY" missed="0" covered="1"/>
	<counter type="METHOD" missed="0" covered="1"/>
</method>
...
<method name="getTableName" desc="()Ljava/lang/String;" line="2841">
	<counter type="INSTRUCTION" missed="3" covered="0"/>
	<counter type="LINE" missed="1" covered="0"/>
	<counter type="COMPLEXITY" missed="1" covered="0"/>
	<counter type="METHOD" missed="1" covered="0"/>
</method>
<method name="isCached" desc="()Z" line="2982">
	<counter type="INSTRUCTION" missed="8" covered="0"/>
	<counter type="BRANCH" missed="2" covered="0"/>
	<counter type="LINE" missed="1" covered="0"/>
	<counter type="COMPLEXITY" missed="2" covered="0"/>
	<counter type="METHOD" missed="1" covered="0"/>
</method>
<method name="purgeCache" desc="()V" line="2990">
	<counter type="INSTRUCTION" missed="3" covered="0"/>
	<counter type="LINE" missed="2" covered="0"/>
	<counter type="COMPLEXITY" missed="1" covered="0"/>
	<counter type="METHOD" missed="1" covered="0"/>
</method>
<counter type="INSTRUCTION" missed="186" covered="523"/>
<counter type="BRANCH" missed="3" covered="17"/>
<counter type="LINE" missed="52" covered="65"/>
<counter type="COMPLEXITY" missed="42" covered="39"/>
<counter type="METHOD" missed="40" covered="31"/>
<counter type="CLASS" missed="0" covered="1"/>

Sonar fails with the error:

[ERROR] Cannot import coverage information for file 'common/src/main/java/app/models/CustomField.java', coverage data is invalid. Error: {}

java.lang.IllegalStateException: Line 177 is out of range in the file common/src/main/java/app/models/CustomField.java (lines: 171)

So we have 0% coverage in Sonar and 73% in JaCoCo

Hi @alniks,

If you exclude the original source file from the analysis using sonar.exclusions and add the generated one using sonar.sources, you could probably import the coverage without errors. But IMO you should completely exclude files having generated code from the coverage using sonar.coverage.exclusions otherwise you will have uncovered lines in the generated code that you will never be able to cover.

In my case the error was caused by:

  • two files with the same name Foo.java
  • in the same package com.bar.baz
  • with different content (especially number of lines)

This may be related to having different (Gradle) subprojects, or having code duplication for test fixture code. My fix was to rename the files or move them to different packages (while I still tackle the underlying duplication issue).