One of the most frustrating challenges developers face when adopting the Java Platform Module System (JPMS) is dealing with module resolution errors. Common issues include “package is not visible,” “module not found,” or conflicts caused by mixing classpath and module path. These errors often confuse developers transitioning from monolithic JAR deployments to modular applications.
Understanding and resolving these issues is critical in real-world projects where enterprise systems, microservices, or legacy monoliths are being modularized. Proper debugging ensures smoother builds, faster deployment pipelines, and more reliable modular applications.
Think of module resolution like a conference guest list: if someone’s name isn’t on the list, they don’t get access. If they’re on the list but don’t have the right badge, they can’t enter certain rooms. Debugging module resolution errors is about ensuring everyone is correctly listed, identified, and authorized.
Common Module Resolution Errors
1. Module Not Found
Error: module com.example.app not found
Occurs when the module path does not include the required module.
Fix:
- Ensure the module JAR is on the
--module-path
- Verify
module-info.java
is correctly defined
2. Package Not Visible
Error: package com.example.internal is not visible
Occurs when trying to access a non-exported package.
Fix:
- Export the package explicitly in
module-info.java
module com.example.lib {
exports com.example.api; // only API is visible
}
3. Duplicate Module
Error: duplicate module: com.example.lib
Occurs when the same module appears multiple times on the module path.
Fix:
- Remove duplicates from the module path
- Consolidate dependencies in build tools like Maven/Gradle
4. Mixed Classpath and Module Path
Error: java.lang.module.FindException: Module not found
Occurs when dependencies are placed incorrectly on the classpath instead of module path.
Fix:
- Place modular JARs on the module path
- Use classpath only for non-modular libraries
5. Automatic Modules Conflicts
Automatic modules are generated when plain JARs are placed on the module path. Conflicts arise when:
- Names clash
- Transitive dependencies are missing
Fix:
- Prefer modular JARs
- Use
--patch-module
or modularize critical dependencies
Tools for Debugging
jdeps
→ Analyze module dependencies
jdeps --module-path mods --check com.example.app
--show-module-resolution
→ Display how modules are resolved at runtime
java --show-module-resolution -p mods -m com.example.app/com.example.Main
--list-modules
→ List all available modules in a runtime image
java --list-modules
Best Practices
✅ Always define module-info.java
explicitly
✅ Use jdeps
to analyze dependency graphs
✅ Keep third-party libraries modular where possible
✅ Automate checks in CI/CD pipelines
❌ Avoid relying on automatic modules long-term
❌ Don’t mix classpath and module path without care
❌ Don’t export internal packages unless absolutely necessary
What's New in Java Versions?
- Java 5–8 → N/A (Modules introduced in Java 9)
- Java 9 → JPMS introduced, along with common resolution challenges
- Java 11 → Improved tooling for debugging module issues
- Java 17 → Performance and stability improvements in JPMS
- Java 21 → No significant updates across Java versions for this feature
Real-World Analogy
Debugging module resolution errors is like managing airport security checks. Passengers (modules) must have:
- A valid boarding pass (declared in module-info)
- Correct gate assignment (module path)
- No duplicates or impersonations (duplicate modules)
If one condition fails, access is denied.
Summary & Key Takeaways
- Module resolution errors are common during JPMS adoption
- Errors include missing modules, visibility issues, duplicate modules, and classpath conflicts
- Tools like
jdeps
and--show-module-resolution
are essential for debugging - Follow best practices to avoid long-term headaches
- Proper debugging ensures smooth modular deployments
FAQ: Debugging Module Resolution Errors
1. What is the difference between the classpath and module path?
Classpath loads everything without visibility rules, while module path enforces strong boundaries.
2. Why do I get “package is not visible” errors?
Because JPMS requires explicit exports
declarations for package visibility.
3. What does requires transitive
do?
It makes dependencies available to modules further down the chain.
4. What’s the difference between open
and opens
?open
opens the entire module for reflection, opens
targets specific packages.
5. What are automatic modules?
Non-modular JARs treated as modules. Useful for migration but risky long-term.
6. How does JPMS improve security compared to classpath?
By enforcing strict boundaries and preventing accidental access to internals.
7. When should I use jlink vs jmod?jmod
is for packaging modules, jlink
for building custom runtime images.
8. Can I modularize incrementally?
Yes, start with key components and use automatic modules as a bridge.
9. How do I handle third-party non-modular libraries?
Use them on the classpath or convert them into automatic modules.
10. Do frameworks like Spring and Hibernate support modules?
Yes, but some configurations may need tweaks for full JPMS compatibility.