Back to Exceptions in Constructors & Static Init
Q2Question 2 of 2

What is ExceptionInInitializerError?

Key Concepts
  • If a static initializer throws an unchecked exception, the JVM wraps it in ExceptionInInitializerError
  • The class is permanently marked as failed and can never be used again in that JVM instance
  • Every subsequent access to the class throws NoClassDefFoundError, not the original error
  • The real cause is only visible in the FIRST error (ExceptionInInitializerError via getCause())
  • Fix: use lazy initialization instead of static init blocks, or catch exceptions inside the static block
  • Only a JVM restart can recover a class that failed static initialization

Definition

When a static initializer throws, the JVM wraps it in ExceptionInInitializerError, permanently marks the class as failed, and every subsequent access throws NoClassDefFoundError with the original cause lost.
  • If a static initializer block or static field initialization throws an unchecked exception, the JVM wraps it in ExceptionInInitializerError.
  • The class is permanently marked as erroneous. It can never be loaded or used again.
  • The first access shows the real cause via e.getCause(). Every subsequent access throws NoClassDefFoundError with no useful message.
  • Only a JVM restart can recover the class.
  • Fix: use lazy initialization (initialize on first method call, not at class load), or catch all exceptions inside the static block.

The bank vault's security system is configured during construction (static init). If configuration fails (exception), the vault is permanently condemned (ExceptionInInitializerError). Every future attempt to open the vault gets "vault does not exist" (NoClassDefFoundError), not "configuration failed." The original error is lost after the first attempt. Only demolishing and rebuilding (JVM restart) can fix it.

Understanding the Concepts

What happens when a static initializer throws?

The JVM wraps the exception in ExceptionInInitializerError and permanently marks the class as failed.

JAVA
package com.bank.demo;

public class StaticInitFailDemo {

    static class BrokenConfig {
        static final int MAX_TRADES = Integer.parseInt("NOT_A_NUMBER");
        // NumberFormatException at class load time.
        // JVM wraps: ExceptionInInitializerError(cause=NumberFormatException)
    }

    public static void main(String[] args) {
        // First access: ExceptionInInitializerError
        try {
            System.out.println(BrokenConfig.MAX_TRADES);
        } catch (ExceptionInInitializerError e) {
            System.out.println("First: " + e.getClass().getSimpleName());
            System.out.println("Cause: " + e.getCause().getClass().getSimpleName());
            System.out.println("Message: " + e.getCause().getMessage());
        }

        // Second access: NoClassDefFoundError (class is DEAD)
        try {
            System.out.println(BrokenConfig.MAX_TRADES);
        } catch (NoClassDefFoundError e) {
            System.out.println("\nSecond: " + e.getClass().getSimpleName());
            System.out.println("Original cause is GONE from this error");
        }
    }
}
TEXT
First: ExceptionInInitializerError
Cause: NumberFormatException
Message: For input string: "NOT_A_NUMBER"

Second: NoClassDefFoundError
Original cause is GONE from this error

How do you fix static initializer failures?

Use lazy initialization instead of static blocks. Initialize on first use, not at class load.

JAVA
package com.bank.demo;

public class LazyInitFixDemo {

    // WRONG: static init fails and class is permanently dead
    // static class DatabasePool {
    //     static final DataSource DS;
    //     static {
    //         DS = createPool();  // throws if DB is down
    //     }
    // }

    // CORRECT: lazy initialization, retryable
    static class DatabasePool {
        private static volatile String dataSource;

        static String getDataSource() {
            if (dataSource == null) {
                synchronized (DatabasePool.class) {
                    if (dataSource == null) {
                        dataSource = createPool();
                    }
                }
            }
            return dataSource;
        }

        private static String createPool() {
            System.out.println("Creating pool (lazy, retryable)");
            return "HikariPool-SAV2001";
        }
    }

    public static void main(String[] args) {
        // Lazy: initialized on first use, not at class load
        String pool = DatabasePool.getDataSource();
        System.out.println("Pool: " + pool);

        // If createPool() fails, the class is still alive.
        // Next call can retry.
    }
}
TEXT
Creating pool (lazy, retryable)
Pool: HikariPool-SAV2001

What is the debugging trick for NoClassDefFoundError?

If you see NoClassDefFoundError for a class that exists on the classpath, search for ExceptionInInitializerError earlier in the logs.

JAVA
package com.bank.demo;

public class DebuggingTrickDemo {

    public static void main(String[] args) {
        System.out.println("Debugging NoClassDefFoundError:");
        System.out.println();
        System.out.println("1. Class EXISTS on classpath but NCDFE thrown?");
        System.out.println("   -> Search logs for ExceptionInInitializerError");
        System.out.println("   -> The EIIE has getCause() with the real error");
        System.out.println("   -> EIIE happens ONCE, all subsequent = NCDFE");
        System.out.println();
        System.out.println("2. Common causes of EIIE:");
        System.out.println("   - Integer.parseInt(badValue) in static field");
        System.out.println("   - DB connection in static block when DB is down");
        System.out.println("   - Missing config file read in static block");
        System.out.println();
        System.out.println("3. Fix: use lazy init or catch inside static block");
    }
}
TEXT
Debugging NoClassDefFoundError:

1. Class EXISTS on classpath but NCDFE thrown?
   -> Search logs for ExceptionInInitializerError
   -> The EIIE has getCause() with the real error
   -> EIIE happens ONCE, all subsequent = NCDFE

2. Common causes of EIIE:
   - Integer.parseInt(badValue) in static field
   - DB connection in static block when DB is down
   - Missing config file read in static block

3. Fix: use lazy init or catch inside static block

What should a senior engineer know?

  • Spring Boot startup. If a @Configuration class has a static initializer that throws, the entire application context fails. The EIIE is in the startup logs.
  • Class reloading. In servlet containers (Tomcat), undeploying and redeploying can trigger fresh class loading, effectively recovering from EIIE without a full JVM restart.
  • Checked exceptions in static blocks. Static initializers cannot throw checked exceptions. You must catch them or wrap in RuntimeException.

What are common interview follow-up questions?

  • What is the relationship between EIIE and NCDFE? (First load throws EIIE, subsequent loads throw NCDFE.)
  • Can you recover a class after EIIE without restarting? (No, the class is permanently marked failed.)
  • How do you prevent EIIE? (Lazy initialization, or catch inside the static block.)
  • Where is the real cause visible? (Only in the first EIIE via getCause().)

Visual Overview

DIAGRAM
  Class First Load:
  static { throw new RuntimeException("config error"); }
       │
       ▼
  JVM wraps in ExceptionInInitializerError
  Class marked: PERMANENTLY FAILED
       │
       ├── First access:  ExceptionInInitializerError
       │                  getCause() → real error (visible)
       │
       ├── Second access: NoClassDefFoundError
       │                  real cause GONE
       │
       ├── Third access:  NoClassDefFoundError
       │                  real cause GONE
       │
       └── Only JVM restart recovers the class

Key Takeaway

When a static initializer or static field initialization throws an unchecked exception, the JVM wraps it in ExceptionInInitializerError and permanently marks the class as erroneous. The first access shows the real cause via getCause(). Every subsequent access throws NoClassDefFoundError with the original cause gone. The class is dead for the lifetime of the JVM.

This is dangerous in production at National Bank of India: a DB outage during startup kills the DatabasePool static initializer. The class is permanently dead. When the DB comes back, every access still throws NoClassDefFoundError. The entire service stays down until the JVM is restarted.

The fix is lazy initialization: initialize resources in a method call on first use, not in static blocks. If initialization fails, the class is still alive and the next call can retry. Another fix is catching all exceptions inside the static block and setting safe defaults.

Remember one sentence: a failed static initializer permanently kills the class, so use lazy initialization instead of static blocks for anything that can fail.

---

Share
Use ← → arrow keys to navigate