Quick answer
Almost always a classpath or working-directory mismatch. From the directory that contains your top-level package folder, run:
java -cp <classes-dir> <fully.qualified.ClassName>
Not a bare class name, and not from inside the package's own folder. If you're running a jar instead, see Fix 3 below — the message you'd get there is different.
The exact error string
$ java Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main
The Caused by line is the real diagnostic: this is a ClassNotFoundException at the JVM's own bootstrap step, before your program has run a single line. javac compiling your source without complaint tells you nothing about whether this specific java invocation can find the resulting .class file — the two are entirely separate tools with no shared awareness of each other's working directory or paths.
Why this happens
java looks for Main.class on the classpath — by default, the current working directory plus anything passed via -cp/-classpath or the CLASSPATH environment variable. If your class declares a package, the JVM expects to find it at a path matching that package under one of those classpath roots — com/example/Main.class under a directory that's on the classpath, not Main.class sitting by itself. Get either the directory or the class name wrong and the class simply isn't where the JVM looked.
Fix 1 (fastest): match your working directory to your classpath
Say Main.java declares package com.example; and you compiled it to an out/ directory:
out/
com/
example/
Main.class
# ❌ wrong directory, wrong (unqualified) class name
$ cd out/com/example
$ java Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main
# ✅ classpath root, fully package-qualified name
$ cd out
$ java com.example.Main
Hello from Main!
Hello from Main! (or whatever your program prints) appearing is the success signal — there's no separate "loaded successfully" message, the JVM just runs your main method. Two mistakes stack in the broken example above: running from inside the package folder instead of the classpath root, and dropping the package prefix from the class name. Either one alone is enough to trigger this error.
If you compiled with javac directly rather than a build tool, the same rule applies to -d: use javac -d out src/com/example/Main.java to get this exact layout in the first place.
Fix 2: explicit classpath with -cp
Running from an arbitrary directory works too, as long as you point -cp at the classes root explicitly:
$ java -cp out com.example.Main
Hello from Main!
# multiple classpath entries (JARs and directories), separated by
# `:` on Linux/macOS or `;` on Windows:
$ java -cp "out:libs/gson-2.11.0.jar" com.example.Main # Linux/macOS
$ java -cp "out;libs/gson-2.11.0.jar" com.example.Main # Windows
This is the form most build tools and IDEs generate under the hood — if the IDE-generated command works but your manual one doesn't, diff them for exactly this: a missing -cp entry or a wrong separator character for your OS.
Fix 3: running a jar (different message if the manifest is missing)
A runnable jar needs a Main-Class entry in its manifest. Note this produces a different error message if the manifest itself is the problem — don't confuse the two:
# jar built WITHOUT a Main-Class manifest entry:
$ java -jar app.jar
no main manifest attribute, in app.jar
# ← this is a DIFFERENT error, not "Could not find or load main class"
# ✅ build with the manifest entry (Maven shade/assembly plugin,
# Gradle `jar { manifest { attributes 'Main-Class': ... } }`,
# or a hand-written MANIFEST.MF passed to `jar cfm`)
$ java -jar app.jar
Hello from Main!
If you land here searching for "could not find or load main class" but your actual message was "no main manifest attribute", you're in the right general area but the fix is different: add Main-Class: com.example.Main to the jar's manifest, not a classpath change.
Fix 4: default (unnamed) package classes
A class with no package declaration lives in Java's "default package" and is invoked without any qualification — but the classpath rule still applies exactly the same way:
# Main.java has NO package declaration
$ javac Main.java # produces Main.class in the same directory
$ java Main # ✅ works — you ARE already at the classpath root
One Windows-specific trap: some filesystems are case-insensitive, so a folder named Main and a class named main can silently coexist locally and then fail the moment the same project builds on a case-sensitive filesystem (Linux CI, macOS in its default configuration for newer volumes). Keep class names and their file/folder names cased consistently regardless of what your local OS tolerates.
Fix 5: the Java Platform Module System (Java 9+)
If your project is modular (has a module-info.java), invocation needs --module-path and -m instead of a plain classpath:
$ java --module-path out -m com.example.app/com.example.Main
Mixing the two invocation styles — passing -cp to a project that expects --module-path, or vice versa — produces this same "could not find or load" error, because the JVM is looking in the wrong kind of path entirely for a modular build.
Three lookalike errors, disambiguated
| Message | What it means | Fix |
|---|---|---|
| Could not find or load main class (this page) | Class never located on the classpath | Fix classpath / working directory / class name |
| no main manifest attribute, in app.jar | Jar found and opened, but no Main-Class declared | Add Main-Class to the manifest |
| UnsupportedClassVersionError | Class found and opened, but compiled for a newer JDK | Raise the runtime JDK or lower the compile target |
Debugging checklist
- ✓ Does the class declare a
package? Use the fully-qualified name, not the bare class name - ✓ Run from the classpath root — the folder containing the top-level package folder, not the package folder itself
- ✓ Explicit
-cppointing at the right directory (and using the right separator,:vs;, for your OS) - ✓ Running a jar? Check
Main-Classis set in the manifest — that's a different message from this one - ✓ Case mismatch between the class name and its file/folder name? Check on a case-sensitive filesystem
- ✓ Modular project? Confirm you're using
--module-path+-m, not a plain-cp - ✓ IDE-only failure? Compare the IDE's generated run command against a working manual one
- ✓ Getting a version-number error instead? That's UnsupportedClassVersionError, a different page
Frequently Asked Questions
How do I fix 'Error: Could not find or load main class'?
Run java from the classpath root — the directory that contains your top-level package folder — using the fully package-qualified class name, not a bare class name and not the .class file's own directory. For a class declared package com.example; that compiled to out/com/example/Main.class, run java -cp out com.example.Main from the directory containing out/, not from inside out/com/example/.
Why does my program compile fine but fail to run with this error?
javac only cares about your source files and produces .class files wherever you tell it to. It has no concept of how you'll later invoke java. The class name, package, and classpath you pass to java are a completely separate, unchecked step — so a compile that succeeds says nothing about whether your run command matches where the class actually landed.
What is the difference between 'Could not find or load main class' and 'no main manifest attribute'?
"Could not find or load main class" comes from java ClassName (or -cp) when the JVM can't locate that class on the classpath at all. "no main manifest attribute, in app.jar" is a completely different message from java -jar app.jar, meaning the jar was found and opened fine, but its META-INF/MANIFEST.MF doesn't declare a Main-Class. The fix for the second is adding Main-Class to the manifest, not a classpath change.
Is 'Could not find or load main class' the same as UnsupportedClassVersionError?
No, and the distinction matters for diagnosis. "Could not find or load main class" means the .class file was never located. UnsupportedClassVersionError means the JVM found and opened the file, then rejected it because it was compiled for a newer Java version than the one running it — a completely different problem with a completely different fix (raise the runtime JDK or lower the compile target).
Why does this happen only in my IDE but not from the terminal, or vice versa?
The IDE's run configuration has its own idea of the working directory and output/classes folder, independent of what a terminal command does. A stale run configuration pointing at an old output path, or a module misconfiguration after a project restructure, produces this error in the IDE even when the equivalent terminal command with the correct classpath works fine — and the reverse is just as common after an IDE auto-fixes its own config.
More Java & backend errors
Browse the full reference for Java, Go, and Rust errors — exact message, cause, and fix.