🔴 The Error You're Seeing

Confirm this matches your console output. If it does, you're in the right place.

ERROR LOG// DOC-DERIVED — verifier output shape stable since Java 7; location/reason blocks vary by offender: java.lang.VerifyError: Bad type on operand stack Exception Details: Location: com/devinhyderabad/report/AuditLogger.log(Ljava/lang/String;)V @12: invokevirtual Reason: Type 'java/lang/String' (current frame, stack[1]) is not assignable to 'int' Current Frame: flags: { } locals: { 'com/devinhyderabad/report/AuditLogger', 'java/lang/String' } stack: { 'com/devinhyderabad/report/AuditLogger', 'java/lang/String', 'int' }

⚡ Quick Fix Works 80% of the time

Identify the class named in Location, find which agent or generator touches it, then upgrade or disable that instrumenter and rebuild the artifact.

# run once with zero agents to prove the app itself is clean java -jar app.jar # bisect agents one by one java -javaagent:jacoco.jar -jar app.jar # VerifyError returns? upgrade jacoco

🧠 Why this Happens

Tap to expand the deep technical explanation

Before executing any method the verifier simulates every branch, tracking the type of each operand-stack slot against a proof built from StackMapTable frames embedded since class-file version 50. If an instruction pops a String where an int must live, or a branch target lacks a valid frame, verification aborts before main runs. Hand-written ASM transformers, obfuscators, AOP weavers, and outdated agents emit frames their authors computed by hand — and get them subtly wrong. The class never runs a single instruction; rejection happens at load/link time.

The HITEC City Parking Spot Analogy:

Airport security inspects every suitcase by X-ray before boarding. One bag contains a battery packed where liquids belong — the whole suitcase is refused at the gate, no matter how fine the contents actually are.

🔁 How to Reproduce Confirm this is your error

Attach an old instrumentation agent (or weave a class with hand-written ASM emitting inconsistent frames), then start the JVM. Verification fires during loading, before any application output. DOC-DERIVED — producing honest VerifyErrors requires deliberately malformed bytecode.

🛠️ Solutions (5 Ways to Fix)

Solution 1✓ Most common cause

Bisect agents and weavers until the offender is isolated

👉 Use this whenever VerifyError appears only under profilers, coverage tools, AOP, or -javaagent flags.

Start the app with no agents, then attach candidates one at a time. The first run that reproduces the error names the guilty instrumenter; upgrading it to a JDK-matching release usually ends the story.

java -jar app.jar # baseline: clean? java -javaagent:aspectjweaver.jar -jar app.jar java -javaagent:jacocoagent.jar -jar app.jar # repeat per agent
Solution 2

Upgrade the bytecode toolkit to match your JDK class-file version

👉 Use this if you own code generating or transforming classes with ASM, Byte Buddy, or Javassist.

Each JDK ships a new class-file format version; older libraries cannot compute frames for what they have never seen. Pin versions known-good for the running JDK (ASM 9.x for recent releases).

<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.7</version> </dependency>
Solution 3

Let ASM recompute frames instead of hand-writing them

👉 Use this if your own transformer produces the invalid frames.

ClassWriter.COMPUTE_FRAMES makes ASM derive StackMapTable entries from a simulated dataflow, eliminating the manual arithmetic that breaks verification. Pass the original ClassReader into the writer so ASM can copy constant-pool context while recomputing frames.

ClassReader reader = new ClassReader(bytes); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); // transform with a ClassVisitor accepting 'reader' and writing into 'writer' byte[] verified = writer.toByteArray();
Solution 4

Re-download or rebuild the corrupt artifact

👉 Use this when the named class should never have been transformed at all.

Truncated jars and partially written target/classes can also fail structural checks. Purge caches, rebuild clean, and compare checksums against the repository metadata.

mvn clean install rm -rf ~/.m2/repository/com/devinhyderabad/report && mvn -U dependency:resolve sha256sum target/app.jar # compare with CI artifact
Solution 5

Disable bytecode verification wholesale

👉 DEV ONLY — never ship this; see below.

DEV ONLY. The flags still launch the JVM on every JDK tested (17 and 25 print a deprecation warning and continue), which makes them seductive — but they turn off the safety net that stops memory-corrupting bytecode, so production JVMs and security policy treat them as handing the keys to whatever jar lands on the classpath next. Use solely to confirm the diagnosis locally; plan for the day the option is deleted.

# DEV ONLY - diagnosis only, absolutely not for deployment java -Xverify:none -jar app.jar # OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify # were deprecated in JDK 13 and will likely be removed in a future release.

📋 Version Notes

Java 8

StackMapTable mandatory since Java 7; most legacy-agent VerifyErrors originate here.

Java 11

Unchanged rules; more frameworks began weaving, raising exposure.

Java 13

-Xverify:none / -noverify deprecated with a startup warning (still functional).

Java 21

Flags still accepted with the same warning (verified on 17.0.19 and 25.0.2) — de facto dead, formally pending removal.

🛡️ How to Prevent This Next Time

Keep the agent/toolchain matrix pinned and tested on every JDK bump, never hand-compute stack maps, and smoke-boot the fully instrumented artifact in CI so verification failures surface before release.