java.lang.ClassNotFoundException: com.example.MissingClass

Short answer

The JVM looked for a class by name at runtime and did not find it on the classpath. On Lambda the classpath is /var/task/ plus /var/task/lib/*.jar plus any layer under /opt, so this almost always means the class is missing from the deployment artifact rather than from your code.

What it means

Java resolves most classes when they are first needed rather than all at once at startup, and it resolves them by name against a classpath. Inside a Lambda execution environment that classpath is fixed: /var/task/, every jar under /var/task/lib/, and anything a layer places under /opt. Nothing from your build machine, your IDE's run configuration, or your local Maven repository is present.

ClassNotFoundException is thrown when something asked the classloader for a class by name and it was not found on that path. The "by name" part matters, and is the reason this error survives a successful compile: reflection, service loaders, dependency-injection frameworks and JSON deserializers all resolve classes from strings at runtime, so the compiler has nothing to check. Lambda itself does exactly this to load your handler, which is why a handler misconfiguration surfaces as a ClassNotFoundException naming your own class.

Because resolution is lazy, the timing of the failure is informative. A class needed to construct your handler fails during init, so every invocation dies the same way and none of your code runs. A class needed only on one branch — an error formatter, an optional integration — fails only when that branch is taken, which produces a deployment that appears healthy until a particular kind of request arrives. Reading the stack trace to see where the load was attempted separates those two immediately.

The distinction worth keeping straight is against its close relative, NoClassDefFoundError. ClassNotFoundException means the class was never found. A NoClassDefFoundError means it was found once, failed to initialise, and every subsequent attempt to use it fails too. They read almost identically in a log and point at completely different problems — one is a packaging fault, the other is usually an exception thrown in a static initialiser.

Counts

CloudWatch’s Errors metric: The error escaped your handler, so Lambda reports the invocation as failed and CloudWatch’s Errors metric counts it. The class cannot be loaded, so the invocation fails and CloudWatch counts it. LogStitch extracts the type ClassNotFoundException but classifies the failure as unclassified rather than uncaught, because Java code can legitimately catch this exception — the log line alone does not say whether anything did.

What it looks like in CloudWatch

This is the shape the failure arrives in: the lines of one invocation scattered among everything else the log group received at the same moment.

CloudWatch Logs Before

7 raw lines, in the order CloudWatch delivered them.

2026-08-29T09:12:03.771Z START RequestId: b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28 Version: $LATEST
2026-08-29T09:12:04.118Z b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28 java.lang.ClassNotFoundException: com.example.orders.PricingRules
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
at com.example.orders.OrderHandler.handleRequest(OrderHandler.java:52)
2026-08-29T09:12:04.402Z END RequestId: b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28
2026-08-29T09:12:04.402Z REPORT RequestId: b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28 Duration: 631.09 ms Billed Duration: 632 ms Memory Size: 1024 MB Max Memory Used: 248 MB Status: error

LogStitch After

The same lines, grouped into the invocation they belong to.

Errorb2c47e91-5a08-4f36-bd12-7e0a3c9f4d28dur 631msbilled 632msmem 248/1024MBlogs 6
  1. 09:12:03.771PLAT
    START RequestId: b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28 Version: $LATEST
  2. 09:12:04.118
    java.lang.ClassNotFoundException: com.example.orders.PricingRules
  3. 09:12:04.118
    	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
  4. 09:12:04.118
    	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
    	at com.example.orders.OrderHandler.handleRequest(OrderHandler.java:52)
    2 lines
  5. 09:12:04.402PLAT
    END RequestId: b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28
  6. 09:12:04.402PLAT
    REPORT RequestId: b2c47e91-5a08-4f36-bd12-7e0a3c9f4d28	Duration: 631.09 ms	Billed Duration: 632 ms	Memory Size: 1024 MB	Max Memory Used: 248 MB	Status: error
Error
Status
631ms
Duration
632ms
Billed
248/1024MB
Memory
76%
Headroom
No
Cold start
ClassNotFoundException
Error type

The panel on the right is generated by running the excerpt on the left through the same parser that powers the free web stitcher — it is what the tool actually produces for this input, not an illustration of it.

How to confirm it from the logs

Read the fully-qualified class name in the message and decide which of two cases you have. If it is your own handler class, Lambda could not load the entry point at all and the handler configuration or the artifact layout is wrong. If it is a third-party class — something under com.amazonaws, org.apache, com.fasterxml — a dependency did not make it into the jar.

The stack trace beneath tells you when it happened. A failure inside URLClassLoader.findClass during init means the class was needed to construct your handler. A failure deeper in your own call stack means it was needed lazily, part-way through a request — which is why some invocations can succeed while others fail on the same deployment.

Causes, most likely first

1

The dependency was not included in the deployment artifact

How to confirm

List the contents of the deployed jar or zip and look for the class's path. A plain jar built by mvn package contains only your own compiled classes — dependencies are not included unless the build is configured to include them, which is the single most common cause here.

2

The handler string does not match the class in the artifact

How to confirm

Compare the configured handler against the actual fully-qualified class name. Lambda expects package.ClassName::methodName, or just package.ClassName when the class implements RequestHandler. A typo, a missing package prefix, or a renamed class produces exactly this error naming your own class.

3

A shaded or relocated dependency moved the class

How to confirm

Check whether the build shades dependencies, and whether the missing class's package looks relocated. Shading rewrites package names inside the jar; anything that loads a class by string name — reflection, a service loader, a framework's configuration — will still ask for the original name and not find it.

4

The class is provided at compile time but not at runtime

How to confirm

Look at the dependency's scope in the build file. A Maven dependency with <scope>provided</scope> or a Gradle compileOnly is on the compile classpath and deliberately excluded from the artifact. That is correct for the Lambda runtime interface itself, and wrong for anything your code actually needs at runtime.

5

Two versions of the same library disagree about what exists

How to confirm

Print the dependency tree and look for the missing class's library appearing more than once. When two versions are present, whichever the classloader reaches first wins, and a class that exists only in the other version becomes unfindable at runtime while compiling perfectly.

Fixes

Fix 1

Build an artifact that actually contains your dependencies

Lambda needs either an uber-jar or a zip with lib/ inside it. The Maven Shade plugin produces the former; the AWS-recommended layout for larger functions is the latter, which unpacks faster on a cold start.

xml<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.5.1</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals><goal>shade</goal></goals>
    </execution>
  </executions>
</plugin>
Fix 2

Confirm the class is present before you deploy again

Checking the artifact takes a few seconds and settles the question of whether this is a build problem or a configuration one.

bash# Is the class actually in there?
unzip -l target/function.jar | grep -i 'MissingClass'

# And what does the handler string need to match?
unzip -p target/function.jar META-INF/MANIFEST.MF
Fix 3

Check the handler configuration against the real class name

When the missing class is your own, the artifact is usually fine and the handler string is not. It must be the fully-qualified name, package included.

yamlResources:
  OrderFunction:
    Type: AWS::Serverless::Function
    Properties:
      # package.Class::method — the package prefix is required
      Handler: com.example.orders.OrderHandler::handleRequest
      Runtime: java21
Fix 4

Resolve duplicate versions before assuming the class is absent

Where the dependency tree shows a library twice, pin it once explicitly. A class that exists in one version and not the other will otherwise resolve differently depending on classloader order, which makes the failure look intermittent.

bashmvn dependency:tree -Dverbose -Dincludes=com.fasterxml.jackson.core

Also seen as

The same underlying failure, worded differently by a different runtime, SDK version, or logging layer. All of these land here — there is no separate page for each phrasing.

Class not found: com.example.Handlerjava.lang.ClassNotFoundException: com.amazonaws.services.lambda.runtime.RequestHandlerlambda java class not foundlambda handler class not found

Errors that show up alongside this one, or that people mistake for it.

References

LogStitch finds this automatically, across every invocation in your account.

Paste a log excerpt into the free web stitcher and see it grouped, classified, and measured in your browser — nothing is uploaded. Or run the Mac app against your own AWS profiles and get the same view over every function you own.