Skip to content

Lambda layer contents not showing up in /opt

0

I created a lambda layer by importing a zip file. This file was of a directory (certs) and had a .pem file in it. I understood that this would place a certs directory under /opt and the file would be there. In my lambda function I set and environment variable to reference /opt/certs/whatever.pem but I get an error saying the file doesn't exist. (NODE_EXTRA_CA_CERTS - should allow a third party cert with fetch).

I added :

const output = execSync('ls -R /opt').toString(); console.log("Contents of /opt:\n" + output);

to try to see contents of /opt, but it shows up as empty in cloudwatch

2025-10-09T22:25:52.750Z 69ce2e6b-d468-4125-b60e-03d4ef44fdec INFO Contents of /opt: /opt:

Also from cloudwatch:

Warning: Ignoring extra certs from /opt/certs/whatever.pem, load failed: error:80000002:system library::No such file or directory

Was my understanding of the pathing wrong or dated? Where would I find this file? (Using Node.js)

Update: I also changed my method to read from the file system from execSync to using readdirSync and looping through returned files list, (javascript) readdirSync returns an empty list.

code snippet (taken from internet search), inside try/catch so no error is being thrown....

const files = readdirSync('/opt', { withFileTypes: true }); // Or just '/opt' if not a Node.js specific layer console.log('Contents of /opt:'); // this prints for (const file of files) { console.log(${file.isDirectory() ? 'DIR' : 'FILE'}: ${file.name}); // this doesn't }

asked 9 months ago298 views

2 Answers
0
Accepted Answer

Hello.

I added a layer to my AWS account using the steps in the document below and confirmed that files were created under "/opt".
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-layers.html

I added the layer by running the following AWS CLI command:

mkdir nodejs
cd nodejs
mkdir certs
cd certs/
openssl genrsa -out whatever.pem 2048
cd ../../
zip -r layer.zip nodejs
aws lambda publish-layer-version --layer-name cert --zip-file fileb://layer.zip --compatible-runtimes nodejs22.x --region your-region
aws lambda update-function-configuration --function-name nodetest --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:your-region:your-aws-account-id:layer:cert:1"

I used the following code to check the files in "/opt".

import fs from 'fs';
import path from 'path';

export const handler = async (event) => {
  const targetDir = '/opt';
  
  try {
    const listFiles = (dir) => {
      const entries = fs.readdirSync(dir, { withFileTypes: true });
      const results = [];

      for (const entry of entries) {
        const fullPath = path.join(dir, entry.name);
        if (entry.isDirectory()) {
          results.push(...listFiles(fullPath));
        } else {
          results.push(fullPath);
        }
      }
      return results;
    };

    const files = listFiles(targetDir);

    console.log("===== /opt file list =====");
    console.log(files);

    return {
      statusCode: 200,
      body: JSON.stringify({
        message: `/opt contains ${files.length} file(s).`,
        files,
      }),
    };
  } catch (err) {
    console.error("Error reading /opt:", err);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: err.message }),
    };
  }
};

As a result of execution, you can confirm that the following files have been created:

{
  "statusCode": 200,
  "body": "{\"message\":\"/opt contains 1 file(s).\",\"files\":[\"/opt/nodejs/certs/whatever.pem\"]}"
}
EXPERT

answered 9 months ago

AWS
EXPERT

reviewed 9 months ago

  • I had created the layer via the AWS UI instead of the CLI. This answer led me to two actions. First, I recreated the layer using the nodejs path as mentioned above. I'm not sure this was absolutely necessary given the other answer generated by AWS AI (...) didn't include that portion in the description of the use of /opt/lib. But, following my belief that working code wins I recreated the layer with the new path. The second piece it led me to was how to actually add the layer to the function. I had to look further into the UI than I had previously (scroll bars are a wonderful thing) to see where to add the layer to my function.

    This is my first lambda function and my first layer, so obviously a newbie mistake.

    Thanks for the pointers here.

0

When you add a layer to a Lambda function, Lambda does extract the layer contents into the /opt directory, but there's a specific directory structure you need to follow for your layer content to be properly recognized.

For Node.js runtimes, your layer .zip file should have its dependencies in one of these folder paths:

  • nodejs/node_modules
  • nodejs/node18/node_modules
  • nodejs/node20/node_modules
  • nodejs/node22/node_modules

It appears that you zipped the certs directory directly, which isn't following the expected structure. When Lambda extracts this, it's not placing it in a location where your function can find it.

To fix this issue, you have two options:

  1. Update your reference path: If you want to keep your current layer structure, you should reference the file using the full path where Lambda actually placed it. Try checking for the file in subdirectories of /opt.

  2. Restructure your layer: The better approach is to restructure your layer .zip file. For non-code assets that should be accessible to all runtimes, you can place them in the lib directory within your .zip file. Lambda will extract this to /opt/lib.

For your specific case with a certificate file, try creating a .zip file with this structure:

lib/
certs/
whatever.pem

Then update your environment variable to point to /opt/lib/certs/whatever.pem.

Remember that when you're creating a layer, the directory structure inside the .zip file is important for Lambda to correctly place your files where your function can access them.
Sources
Managing Lambda dependencies with layers - AWS Lambda
Loading a csv file in a Lambda layer | AWS re:Post
Packaging your layer content - AWS Lambda
Deploy Node.js Lambda functions with .zip file archives - AWS Lambda

answered 9 months ago

  • I recreated my zip file to include lib as directed above, deleted and recreated my layer, changed my environment variable as directed above. No change in behavior, ls -R /opt still seems to return empty list. File (with new path) still shows load failure.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.