cyberangles blog

ClassNotFoundException: org.flywaydb.core.api.callback.FlywayCallback in Spring Boot: Why It Happens & How to Fix

If you’re working with Spring Boot and Flyway for database migrations, encountering a ClassNotFoundException: org.flywaydb.core.api.callback.FlywayCallback can be frustrating. This error typically surfaces during application startup, halting your development or deployment process. But fear not—this blog will break down why this error occurs and provide a step-by-step guide to fix it for good.

Whether you’re a seasoned developer upgrading dependencies or a beginner setting up Flyway for the first time, understanding the root cause and solution will save you hours of debugging. Let’s dive in!

2026-02

Table of Contents#

  1. What is ClassNotFoundException: FlywayCallback?
  2. Why Does This Error Happen?
  3. How to Fix the Error
  4. Troubleshooting Common Issues
  5. Conclusion
  6. References

What is ClassNotFoundException: FlywayCallback?#

A ClassNotFoundException occurs when the Java Virtual Machine (JVM) tries to load a class but cannot find its definition in the classpath. In this case, the missing class is org.flywaydb.core.api.callback.FlywayCallback—an interface used in Flyway, a popular database migration tool, to define custom callbacks (e.g., logic to run before/after migrations).

If your Spring Boot application throws this error, it means:

  • Your code references FlywayCallback explicitly (e.g., a custom callback class implementing it).
  • The JVM cannot locate this class in the runtime classpath.

Why Does This Error Happen?#

To resolve the error, we first need to understand why the FlywayCallback class is missing. Let’s break down the most common causes:

1. Flyway Version Incompatibility#

Flyway frequently updates its API, and version 9.0.0 (released in 2022) introduced breaking changes to its callback system. Prior to Flyway 9, the callback interface was named FlywayCallback and lived in the package org.flywaydb.core.api.callback.

If your application:

  • Uses Flyway 9.0.0 or later, and
  • Contains code that references FlywayCallback (from pre-9 versions),

the JVM will throw ClassNotFoundException because FlywayCallback was removed in Flyway 9.

2. Deprecated API: Flyway 9+ Renamed the Callback Interface#

In Flyway 9, the FlywayCallback interface was renamed to Callback (same package: org.flywaydb.core.api.callback). This was part of a broader effort to simplify the API and align with modern Java conventions.

Example:

  • Pre-Flyway 9: public class MyCallback implements FlywayCallback { ... }
  • Flyway 9+: public class MyCallback implements Callback { ... }

If you haven’t updated your callback classes to use Callback instead of FlywayCallback, the old interface name will no longer resolve.

3. Dependency Misconfiguration#

Spring Boot uses "starters" to auto-manage dependencies. The spring-boot-starter-flyway starter includes Flyway by default, but version mismatches can still occur:

  • Explicit Flyway Version Override: If you manually specify an older Flyway version in your pom.xml/build.gradle but your code uses Callback (Flyway 9+), or vice versa.
  • Transitive Dependencies: A third-party library might pull in an outdated Flyway version, conflicting with your application’s expected version.

How to Fix the Error#

Now that we understand the root causes, let’s walk through fixing the error step-by-step.

Step 1: Identify Your Flyway Version#

First, confirm which Flyway version your application is using. This determines whether FlywayCallback (pre-9) or Callback (9+) is correct.

For Maven:#

Run this command to list all dependencies and their versions:

mvn dependency:tree | grep flyway  

For Gradle:#

Run:

./gradlew dependencies | grep flyway  

Look for a line like:

org.flywaydb:flyway-core:9.16.3  # Flyway 9+ (uses Callback)  
# OR  
org.flywaydb:flyway-core:8.5.13  # Pre-Flyway 9 (uses FlywayCallback)  

Step 2: Update Callback Code to Use the New API#

If you’re on Flyway 9+, replace all references to FlywayCallback with Callback. Here’s how:

Example: Old Callback (Pre-Flyway 9)#

import org.flywaydb.core.api.callback.FlywayCallback;  
import org.flywaydb.core.api.callback.Context;  
import org.flywaydb.core.api.callback.Event;  
 
public class LegacyFlywayCallback implements FlywayCallback {  
 
    @Override  
    public void beforeMigrate(Context context) {  
        System.out.println("Running before migrations...");  
    }  
 
    // Other methods (beforeClean, afterMigrate, etc.)  
}  

Updated Callback (Flyway 9+)#

Flyway 9+ simplifies the callback interface. The Callback interface has a single method: handleEvent(Event event, Context context). Use the Event enum to check when to trigger logic:

import org.flywaydb.core.api.callback.Callback;  // New interface name  
import org.flywaydb.core.api.callback.Context;  
import org.flywaydb.core.api.callback.Event;  
 
public class ModernFlywayCallback implements Callback {  
 
    @Override  
    public void handleEvent(Event event, Context context) {  
        if (event == Event.BEFORE_MIGRATE) {  // Check the event type  
            System.out.println("Running before migrations...");  
        }  
        // Handle other events (e.g., AFTER_MIGRATE, BEFORE_CLEAN) as needed  
    }  
 
    // Optional: Override to specify if the callback applies to all databases  
    @Override  
    public boolean supports(Event event, Context context) {  
        return true;  // Applies to all events/databases  
    }  
}  

Step 3: Adjust Dependencies (If Needed)#

If your Flyway version is misaligned with your code, fix your build configuration to ensure consistency.

Spring Boot’s spring-boot-starter-flyway starter automatically includes a compatible Flyway version. Avoid explicitly defining flyway-core unless necessary:

Maven (pom.xml):

<dependencies>  
    <!-- Let Spring Boot manage Flyway version -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-flyway</artifactId>  
    </dependency>  
</dependencies>  

Gradle (build.gradle):

dependencies {  
    implementation 'org.springframework.boot:spring-boot-starter-flyway'  
}  

Override Flyway Version (If Required)#

If you need a specific Flyway version (e.g., to downgrade to 8.x), explicitly set it in your build file. Ensure your code uses FlywayCallback (not Callback) in this case:

Maven:

<properties>  
    <!-- Force Flyway 8.5.13 (pre-9) -->  
    <flyway.version>8.5.13</flyway.version>  
</properties>  
 
<dependencies>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-flyway</artifactId>  
    </dependency>  
</dependencies>  

Step 4: Verify the Fix#

After updating your code and dependencies:

  1. Rebuild your application (e.g., mvn clean package or ./gradlew build).
  2. Run the application. The ClassNotFoundException should no longer occur.
  3. Test your custom callbacks to ensure they trigger as expected (e.g., check logs for "Running before migrations...").

Troubleshooting Common Issues#

Issue 1: Multiple Callback Implementations#

If you have multiple callback classes, ensure all of them use Callback (Flyway 9+) or FlywayCallback (pre-9). Mixing old and new interfaces will cause errors.

Issue 2: Transitive Dependency Conflicts#

If a third-party library pulls in an outdated Flyway version, use your build tool to enforce the correct version:

Maven: Use <dependencyManagement> to override transitive versions:

<dependencyManagement>  
    <dependencies>  
        <dependency>  
            <groupId>org.flywaydb</groupId>  
            <artifactId>flyway-core</artifactId>  
            <version>9.16.3</version>  <!-- Enforce Flyway 9+ -->  
        </dependency>  
    </dependencies>  
</dependencyManagement>  

Gradle: Use resolutionStrategy in build.gradle:

configurations.all {  
    resolutionStrategy {  
        force 'org.flywaydb:flyway-core:9.16.3'  
    }  
}  

Issue 3: Spring Boot Auto-Configuration#

Spring Boot auto-detects Flyway callbacks in the classpath. If your callback isn’t triggering, ensure:

  • It’s annotated with @Component (so Spring detects it).
  • The supports() method (in Flyway 9+) returns true for the events you care about.

Conclusion#

The ClassNotFoundException: FlywayCallback error in Spring Boot is almost always caused by version incompatibility between your code and Flyway. Flyway 9+ renamed FlywayCallback to Callback, so updating your callback classes and aligning dependencies will resolve the issue.

By following the steps above—identifying your Flyway version, updating callback code, and ensuring dependency consistency—you’ll have your application running smoothly again.

References#