Of course. A java.lang.VerifyError is a common but often confusing runtime exception in Java. Let's break it down in detail, from what it is to how to diagnose and fix it.

What is a VerifyError?
A VerifyError is a LinkError, which is itself a subclass of Error. This is a critical distinction.
-
When it occurs: It happens at link time, which is the phase after compilation but before execution. The Java Virtual Machine (JVM) loads the class file and performs several checks to ensure it is safe and valid before running it. The
VerifyErrorindicates that one of these safety checks has failed. -
The Core Problem: The bytecode in your
.classfile is structurally invalid or violates the JVM's fundamental security and integrity rules. The JVM's bytecode verifier is like a security guard that inspects every class file before it's allowed to run. If the guard finds something suspicious, it throws aVerifyErrorto prevent potentially dangerous code from executing. -
Why is it an
Errorand not anException? Because it signifies a severe problem with the compiled code itself, not a logical error in your program's flow (like anArrayIndexOutOfBoundsException). It's not meant to be caught by your application code; it's a signal that something is fundamentally wrong with the class file.
(图片来源网络,侵删)
What Causes a VerifyError?
Historically, VerifyError was rare because the compiler (javac) would catch most errors. However, with modern development practices, it has become more common. Here are the primary causes, from most to least frequent.
Cause 1: The Most Common Culprit - Bytecode Manipulation
This is the #1 cause today. Any tool or library that modifies Java bytecode at runtime or build time can introduce errors.
- Mocking Libraries: Frameworks like Mockito, EasyMock, or PowerMock generate bytecode on the fly to create mock objects. If you use them incorrectly, they can produce bytecode that the verifier can't understand.
- Example: Trying to mock a
finalclass or aprivatemethod (before certain Java versions) can lead to invalid bytecode.
- Example: Trying to mock a
- AOP (Aspect-Oriented Programming) Libraries: Spring AOP uses bytecode manipulation (via CGLIB or AspectJ) to create proxies for your beans. Issues in pointcut expressions or aspects can lead to verification failures.
- Serialization Libraries: Libraries like Kryo or Protobuf can generate custom serializers that might produce bytecode the verifier dislikes.
- Build Tools and Plugins: Tools that repackage or recompile code, like Maven Shade Plugin or ProGuard, can sometimes corrupt bytecode if not configured correctly.
Cause 2: Corrupted or Incomplete Class Files
This can happen if your build process fails or is interrupted.
- Incomplete Build: If your IDE (like IntelliJ or Eclipse) or build tool (Maven/Gradle) fails to compile a file but still generates a (now invalid)
.classfile, the JVM will fail to verify it. - Network Issues: In some rare cases, downloading dependencies over an unstable network can result in corrupted class files.
Cause 3: Java Version Mismatch (The "Classic" Cause)
This was the most common cause in the past and still happens.

- Compiled on a newer JDK, running on an older JRE: You compile your code with Java 11, which uses new bytecode instructions. You then try to run it on a server that only has Java 8 installed. The Java 8 JVM doesn't understand the new instructions and will throw a
VerifyError. - Example: You use a
var(local variable type inference) feature introduced in Java 10 to compile your code. If you try to run that class on Java 8, you'll get aVerifyError.
Cause 4: Hand-Edited Bytecode
If you manually edit a .class file (e.g., with a hex editor) and break its internal structure, the verifier will reject it. This is extremely rare for most developers.
How to Diagnose and Fix a VerifyError
When you see a VerifyError, the stack trace is your best friend, but it can be misleading. Here’s a step-by-step guide to track it down.
Step 1: Read the Stack Trace Carefully
The stack trace will tell you which class file failed to load. Look for this line:
java.lang.VerifyError: (class: my/package/MyClass, method: signature: V) Incompatible object argument for function call
class: my/package/MyClass: This is the file that failed verification. It might be your code or a library's code.method: signature: V: This is the method where the problem was detected. TheVmeans it's avoidmethod.
Step 2: Check for Version Mismatches (The Easy Check)
This is the first thing you should always check.
- Check your build environment's JDK version:
# In your terminal java -version javac -version
- Check your runtime environment's JRE/JDK version:
# Where your application is actually running java -version
- Check your project configuration:
- Maven: Look at the
<java.version>in yourpom.xmland ensure it matches the target runtime. - Gradle: Look at
sourceCompatibilityandtargetCompatibilityin yourbuild.gradle. - IDE: Ensure your project's SDK is correctly set and matches the runtime.
- Maven: Look at the
If they don't match, you need to align them. You might need to recompile your code on the correct version or upgrade the runtime.
Step 3: Suspect Bytecode Manipulation Libraries (The Most Likely Cause)
If the versions match, the problem is almost certainly a bytecode manipulation library.
- Look at the stack trace class: Is the failing class something you wrote, or does it look like it was generated (e.g.,
MyClass$$EnhancerByCGLIB...orMyClass$MockitoMock$...)? - Review your dependencies:
- Are you using Mockito, Spring AOP, CGLIB, or another library that generates bytecode?
- Have you recently updated any of these libraries? A version incompatibility between a core library and an AOP/mocking library is a very common source of problems.
- Simplify and Isolate:
- Temporarily disable mocking or AOP. Can you run your application without the
@Mockannotations or without a specific aspect? If the error goes away, you've found the source. - Check library compatibility: Ensure the versions of your mocking/AOP libraries are compatible with your version of Spring, Hibernate, or other core frameworks.
- Temporarily disable mocking or AOP. Can you run your application without the
Step 4: Force a Clean Build
A corrupted class file from a previous failed build is a simple but persistent problem.
- In Maven:
mvn clean compile # or for a full refresh mvn clean install
- In Gradle:
gradle clean build
- In an IDE:
- IntelliJ:
Build -> Cleanand thenBuild -> Rebuild Project. - Eclipse:
Project -> Clean....
- IntelliJ:
Step 5: Advanced - Enable Verbose Output
If you're still stuck, you can ask the JVM for more details about the verification process. Use the -Xverify:all flag. This is verbose and can be slow, but it might give you a more specific error message.
java -Xverify:all -jar my-application.jar
Practical Example: Mockito and a Final Class
Let's say you have this code:
// FinalClass.java
package my.package;
public final class FinalClass {
public String doSomething() {
return "real";
}
}
And your test tries to mock it:
// MyTest.java
package my.package;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MyTest {
@Test
public void testMockFinalClass() {
// This will likely cause a VerifyError at runtime
FinalClass mock = mock(FinalClass.class);
when(mock.doSomething()).thenReturn("mocked");
System.out.println(mock.doSomething());
}
}
What Happens:
- Mockito tries to generate a subclass of
FinalClassat runtime. - However, Java does not allow you to extend a
finalclass. - Mockito's bytecode generation fails or produces invalid bytecode.
- When the test runs, the JVM tries to load the generated mock class.
- The bytecode verifier inspects the class and finds a structural violation (e.g., an attempt to extend a final class).
- The JVM throws a
java.lang.VerifyError.
The Fix:
- Don't mock final classes. This is the best practice.
- Use a Mockito extension: If you absolutely must, use a Mockito extension like Mockito-inline or Mockito-inline-extension which uses a different mechanism (redefinition instead of subclassing) to mock final classes and private methods.
By adding the mockito-inline dependency, Mockito can bypass the final restriction in a way that produces valid bytecode, and your test will pass.
