13

Faced this java.lang.VerifyError with code snippet as below during JVM loading bytecode.

try{
-----
}  catch (NumberFormatException|CalculationException e) {

}

Here CalculationException is custom exception which extends java.lang.RuntimeException, while NumberFormatException is standard Java RuntimeException. While the code compile and run fine locally windows machine.

It fails with VerifyError on one of the QA/prod/Dev unix node, and works fine on other unix node. While both unix nodes have the same config (using RedHat 6.2 and 1.8 jdk and same version jar files) also compared the bytecode generated on both nodes by javap -c and found this same.

I found two ways to resolve this on erroneous node also.

1) As this error is coming at byte-code verification step, tried by disabling the bytecode verification on dev unix box as -Xverify:none (Also tried -XX:-UseSplitVerifier but dint work, as i think its disabled from jdk 8) However as we shall not disable bytecode verification in prod, have been looking for some other workaround.

2) Another workaround is by using the parent exception: RuntimeException in catch block instead of combining two exception.

What I am not able to understand if Java does have issue with this way of catching, why compiler dint complained it and why it works on one machine and not on other which have same config. Also the error reason is not making sense which says: CalculationException (current frame, stack[0]) is not assignable to 'java/lang/RuntimeException While its actually assignable as tested by

if (RuntimeException.class.isAssignableFrom(CalculationException.class)){
    System.out.println("Assisgnable");
}

Full Exception Details: Location:

    com/markit/valuations/marketdata/snapper/domain/credit/BeanWrapperBuilder_CDXOCompositeVolSurface.getSpreadVol(Lcom/markit/valuations/dates/ImmutableDate;Lcom/markit/valuations/marketdata/data/indexeddata/IndexedData;DLcom/markit/valuations/dates/ImmutableDate;Lcom/markit/valuations/dates/ImmutableDate;Ljava/lang/String;Ljava/lang/String;Lcom/markit/qag/analytics/credit/indexpv/swaption/CreditIndexSwaptionCalculator;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Double; @51: astore
  Reason:
    Type 'com/markit/valuations/common/CalculationException' (current frame, stack[0]) is not assignable to 'java/lang/RuntimeException' (stack map, stack[0])
  Current Frame:
    bci: @0
    flags: { }
    locals: { 'com/markit/valuations/marketdata/snapper/domain/credit/BeanWrapperBuilder_CDXOCompositeVolSurface', 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/marketdata/data/indexeddata/IndexedData', double, double_2nd, 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/dates/ImmutableDate', 'java/lang/String', 'java/lang/String', 'com/markit/qag/analytics/credit/indexpv/swaption/CreditIndexSwaptionCalculator', 'java/lang/String', 'java/lang/String' }
    stack: { 'com/markit/valuations/common/CalculationException' }
  Stackmap Frame:
    bci: @51
    flags: { }
    locals: { 'com/markit/valuations/marketdata/snapper/domain/credit/BeanWrapperBuilder_CDXOCompositeVolSurface', 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/marketdata/data/indexeddata/IndexedData', double, double_2nd, 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/dates/ImmutableDate', 'java/lang/String', 'java/lang/String', 'com/markit/qag/analytics/credit/indexpv/swaption/CreditIndexSwaptionCalculator', 'java/lang/String', 'java/lang/String' }
    stack: { 'java/lang/RuntimeException' }
  Bytecode:
    0x0000000: 2c19 0ab9 0015 0200 b800 cb2b 1906 ba00
    0x0000010: cc00 00b6 00cd ba00 ce00 00b6 00cf 1909
    0x0000020: ba00 d000 00b6 00cf 0eb8 003b b600 d1c0
    0x0000030: 0091 b03a 0cbb 0048 59b7 0049 12d3 b600
    0x0000040: 4b19 0ab6 004b 12d4 b600 4b2c 1254 b900
    0x0000050: 1502 00b6 004b 12d5 b600 4b29 b600 4c12
    0x0000060: d6b6 004b 1907 b600 4b12 d7b6 004b 1905
    0x0000070: b600 5b12 d8b6 004b 1906 b600 5b12 d9b6
    0x0000080: 004b 190b b600 4b12 dab6 004b 1908 b600
    0x0000090: 4bb6 004d 3a0d b200 4719 0d19 0cb9 0081
    0x00000a0: 0300 0eb8 003b b0
  Exception Handler Table:
    bci [0, 50] => handler: 51
    bci [0, 50] => handler: 51
  Stackmap Table:
  same_locals_1_stack_item_frame(@51,Object[#535])
tarunk
  • 549
  • 2
  • 7
  • 17
  • 3
    The first guess would be that this specific machine has a different version of `CalculationException`. – Holger Feb 21 '19 at 11:20
  • Thanks @Holger, however I had verified the jar version holding CalculationException.class, its same. Even their decompiled code and disassembled code looks same. – tarunk Feb 21 '19 at 12:41
  • Then, there’s no plausible scenario left. As you pointed out, it’s a valid Java construct and it works on one machine. It should work. If it’s not the Java code that is corrupted, perhaps it’s the JDK installation. Besides reinstalling (the equivalent to switching it off and on again), I don’t know what to try… – Holger Feb 21 '19 at 13:09
  • But since it works on erroneous node also by catching the base class exception instead of two exception in catch block as suggested: https://stackoverflow.com/questions/3495926/can-i-catch-multiple-java-exceptions-in-the-same-catch-clause , i thought this is also somewhat linked to java but strange compiler and runtime looks to be behaving differently here. – tarunk Feb 21 '19 at 14:16
  • 1
    Maybe it's a class loader issue. Was the exception ever not a runtime exception in an earlier version? Chances are that you have the artifact twice and load the wrong version from a particular loader. – Rafael Winterhalter Feb 23 '19 at 09:04
  • Thanks Rafel , this looks sensible. Yes earlier it was just an Java.lang.Exception in catch block. However was we have deployed new code how come the class-loader is loading earlier version ? What looks to be is that somehow it has cached the StackMap table from earlier version while loading the bytecode of latest version which has additional exceptions, but not sure how and where it would have cached. – tarunk Feb 23 '19 at 19:20
  • The stackmap table is the right one, as it says that `CalculationException` is supposed to be a subtype of `RuntimeException`, as should be the case with the new version. It could be a class loader issue, but then, it still boils down to [this comment](https://stackoverflow.com/questions/54804355/java-lang-verifyerror-stack-map-does-not-match-the-one-at-exception-handler#comment96387958_54804355)… – Holger Feb 25 '19 at 14:08
  • 4
    +1 for -Xverify:none. I had a similar problem with my Unit Tests in IntelliJ. With this workaround I can debug them again. – anstue Dec 18 '19 at 15:27
  • "it works on one machine and not on other" so much for the Write Once Run Everywhere... – Klesun May 27 '20 at 10:01

3 Answers3

5

Cause

This happened to me when there were conflicting versions of the same library (Jar) in my dependencies. To be more specific, I was importing different versions of Jackson library v2.9.10 and v2.11.0.

Troubleshooting

Start your application in verbose mode and make java log all the classes it is loading to see where the conflicting class is coming from. This can be done by passing the flag -verbose:class

Fix

  • Remove conflicting versions of dependencies and make sure all related dependencies/libraries are of the same major version (at the least) and preferably the same minor version too.
  • Remove dependencies that transitively import conflicting version of direct dependencies.
  • If you are not seeing any conflicting dependencies even after using mvn dependency:tree or Maven Helper plugins, the conflicting dependency could have been imported by one of the libraries' classpath. I know this sounds weird, since only applications should have classpath, but if someone added <addClasspath>true</addClasspath> in their library pom file, it could lead to this.
Aditya Vikas Devarapalli
  • 3,186
  • 2
  • 36
  • 54
  • 1
    For me it was a wrong version of dependency of swagger (which uses jackson) in `plugins` section of `build.gradle`. I was using something that was built for jackson `2.9.10`, on build which included jackson `2.11.3`. I detected the issue using gradle build scans with `--scan`, where I could see the plugins-dependency as separate dependency next to compile-dependencies – arberg Oct 13 '22 at 10:01
0

The dependency crash is the cause as Aditya pointed out. If you are using SBT, here is how you can resolve it.

First, add the dependency graph to your global plugins ~/.sbt/1.0/plugins/plugins.sbt:

  • SBT 1.4+: add
    addDependencyTreePlugin
    
  • SBT <1.3: add
    addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1")
    

Then in your project run

sbt "whatDependsOn com.fasterxml.jackson.core jackson-databind"

were com.fasterxml.jackson.core is the organization and jackson-databind is the artifact name of conflicting library. Mine also was because play-json is using 2.10.4 and Confluent packages use 2.9.9. You have to find yours based on the error messages that you received.

Then from this point forward, you need to make a decision on how to resolve it. Upgrade packages, or downgrade, or exclude libraries. In my scenario, because play-json was transitive dependency from a library that was not really critical in my application, I picked the easiest path and excluded 2.10.4 from play-json library.

Iraj Hedayati
  • 1,478
  • 17
  • 23
-5

you need to set the following jvm args in your config:

-XX:-UseSplitVerifier