Search code examples
amazon-web-servicesaws-lambdaclojureleiningen

java.lang.NoClassDefFoundError: clojure/lang/IFn in aws lambda


I am following a tutorial from aws blogs: https://aws.amazon.com/blogs/compute/clojure/ to run a aws lambda function written in clojure.

I compile the code using lein uberjar which generates the jar files.

Code:

project.clj

(defproject lambda-clj-examples "0.1.0"
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [org.clojure/data.json "0.2.6"]
                 [com.amazonaws/aws-lambda-java-core "1.0.0"]]
  :aot :all)

src/hello.clj

(ns hello
  (:gen-class
   :methods [^:static [handler [String] String]]))

(defn -handler [s]
  (str "Hello " s "!"))

The command to create the function

aws lambda create-function \
  --function-name clj-hello \
  --handler hello::handler \
  --runtime java8 \
  --memory 512 \
  --timeout 10 \
  --role arn:aws:iam::myawsaccountid:role/basic_lambda_role \
  --zip-file fileb://./target/lambda-clj-examples-0.1.0-standalone.jar \
  --region us-east-1

When I go to my function in the aws console, and invoke it, the following message is returned:

{
  "errorMessage": "Error loading class PojoHandler: clojure/lang/IFn",
  "errorType": "java.lang.NoClassDefFoundError"
}

The log output is:

Error loading class hello: clojure/lang/IFn: java.lang.NoClassDefFoundError
java.lang.NoClassDefFoundError: clojure/lang/IFn
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
Caused by: java.lang.ClassNotFoundException: clojure.lang.IFn
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 2 more

To make sure that my standalone jar file has the IFn dependecy, I run

jar tf target/lambda-clj-examples-0.1.0-standalone.jar | grep "IFn.class"

and the output is

clojure/lang/IFn.class

which seems like a good sign.

Should I do something else to make this function work?

Thanks in advance for the help

EDIT: updated lambda creation command with the right handler.

EDIT 2: I realized that my local Java version 11, not Java 8, as @Simon, pointed out in a comment of his answer, this turned out to be the issue.


Solution

  • What's the real command you're using to call create-function? Your pasted example is from the blog which does not substitute awsaccountid. It's possible the JAR is not being uploading to Lambda correctly as a binary object (i.e. wrong path).

    I also don't see where you add POJO handling in hello.clj, since you pass --handler PojoHandler::handlepojo