Node Lambda Local POC Word Template Fill - HandleScope::HandleScope Entering the V8 API without proper locking in place

Product: @pdftron/pdfnet-node

Product Version: 10.5.0

Please give a brief summary of your issue:
Getting error attempting Word Fill POC Locally on Mac

Please describe your issue and provide steps to reproduce it:

I am using a MBP (Ventura 13.5.2 Apple M1 Pro). I am evaluating the Node SDK for Word Fill for eventual use on AWS Lambda but I’m locally trying to get a Lambda working on my mac. I use serverless-offline plugin to run my lambdas locally. I have set esbuild to ignore trying to bundle the @pdftron reference.

I am using Node v18.14.2 locally. I get this fatal error when running.

FATAL ERROR: HandleScope::HandleScope Entering the V8 API without proper locking in place
 1: 0x102158e4c node::Abort() [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 2: 0x102158f44 node::OOMErrorHandler(char const*, bool) [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 3: 0x1022b1b98 v8::HandleScope::HandleScope(v8::Isolate*) [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 4: 0x11c22aee0 pdftron::(anonymous namespace)::OnMessage(uv_async_s*) [/Users/stevehaney/tbcode/tbt-source/api/node_modules/@pdftron/pdfnet-node/lib/addon.node]
 5: 0x102a78e1c uv__async_io [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 6: 0x102a8b5c0 uv__io_poll [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 7: 0x102a792ec uv_run [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 8: 0x1020a9704 node::SpinEventLoop(node::Environment*) [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
 9: 0x10219514c node::NodeMainInstance::Run() [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
10: 0x102126244 node::LoadSnapshotDataAndRun(node::SnapshotData const**, node::InitializationResult const*) [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
11: 0x1021264c8 node::Start(int, char**) [/Users/stevehaney/.nvm/versions/node/v18.14.2/bin/node]
12: 0x1a1567f28 start [/usr/lib/dyld]
Signal received: 6, errno: 0
################################################################################
Stack trace:
################################################################################
1   aws-crt-nodejs.node                 0x0000000119c899bc s_print_stack_trace + 24
2   libsystem_platform.dylib            0x00000001a18eea24 _sigtramp + 56
3   libsystem_pthread.dylib             0x00000001a18bfc28 pthread_kill + 288
4   libsystem_c.dylib                   0x00000001a17cdae8 abort + 180
5   node                                0x0000000102158e58 _ZN4node10FatalErrorEPKcS1_ + 0
6   node                                0x0000000102158f44 _ZN4node15OOMErrorHandlerEPKcb + 0
7   node                                0x00000001022b1b98 _ZN2v811HandleScopeC1EPNS_7IsolateE + 132
8   addon.node                          0x000000011c22aee0 _ZN7pdftron12_GLOBAL__N_19OnMessageEP10uv_async_s + 60
9   node                                0x0000000102a78e1c uv__async_io + 320
10  node                                0x0000000102a8b5c0 uv__io_poll + 1048
11  node                                0x0000000102a792ec uv_run + 404
12  node                                0x00000001020a9704 _ZN4node13SpinEventLoopEPNS_11EnvironmentE + 248
13  node                                0x000000010219514c _ZN4node16NodeMainInstance3RunEv + 196
14  node                                0x0000000102126244 _ZN4node22LoadSnapshotDataAndRunEPPKNS_12SnapshotDataEPKNS_20InitializationResultE + 500
15  node                                0x00000001021264c8 _ZN4node5StartEiPPc + 604
16  dyld                                0x00000001a1567f28 start + 2236
make: *** [up] Error 255

Please provide a link to a minimal sample where the issue is reproducible:

import { ApiSuccess, GenerateErrorResponse } from "@shared/helpers/response-helper";
import { tbMiddlewareInsecure, TbExpandedEvent } from "@shared/middleware/tbMiddleware";
import { PDFNet } from "@pdftron/pdfnet-node"

exports.handler = tbMiddlewareInsecure(async (event: TbExpandedEvent) => {
  try {
    const main = async () => {
      try {
        const sourceDir = "~/Downloads";
        const sourceFile = "letter_template.docx";
        const options = new PDFNet.Convert.OfficeToPDFOptions();

        // Create a TemplateDocument object from an input office file.
        const templateDoc = await PDFNet.Convert.createOfficeTemplateWithPath(`${sourceDir}/${sourceFile}`, options);

        const jObj = {
          applicant_first_name: "Steve",
          applicant_last_name: "Haney",
          table: [
            { "Title": "Web Dev" },
            { "Start Date": "1/1/2030" },
            { "Expected Salary": "$100,00" }
          ]
        };

        // Fill the template with data from a JSON string, producing a PDF document.
        const pdfDoc = await templateDoc.fillTemplateJson(JSON.stringify(jObj));

        const outputFile = `${crypto.randomUUID()}.docx`;

        // Save the PDF to a file.
        await pdfDoc.save(`${sourceDir}/${sourceFile}`, PDFNet.SDFDoc.SaveOptions.e_linearized);
      }
      catch (err) {
        console.error('Failure in PDFTron', err);
      }
    }
    const LICENSE_KEY = "keystring";
    await PDFNet.runWithCleanup(main, LICENSE_KEY);


    return ApiSuccess();
  } catch (error: any) {
    return GenerateErrorResponse(error, "Unhandled failure filling word template");
  }
})

1 Like

Here is a paired down version of the final JS (since I’m using TS).

// src/functions/doc-generation/fill-word-template-apryse.ts
var import_pdfnet_node = require("@pdftron/pdfnet-node");
var import_node_crypto = require("node:crypto");
exports.handler = async (event) => {
  try {
    console.log("doc-generation started");
    const main = async () => {
      try {
        console.log("doc-generation main");
        const sourceDir = "~/Downloads";
        const sourceFile = "letter_template.docx";
        const options = new import_pdfnet_node.PDFNet.Convert.OfficeToPDFOptions();
        const templateDoc = await import_pdfnet_node.PDFNet.Convert.createOfficeTemplateWithPath(`${sourceDir}/${sourceFile}`, options);
        const jObj = {
          applicant_first_name: "Steve",
          applicant_last_name: "Haney",
          table: [
            { "Title": "Web Dev" },
            { "Start Date": "1/1/2030" },
            { "Expected Salary": "$100,00" }
          ]
        };
        const pdfDoc = await templateDoc.fillTemplateJson(JSON.stringify(jObj));
        const outputFile = `${(0, import_node_crypto.randomUUID)()}.docx`;
        await pdfDoc.save(`${sourceDir}/${sourceFile}`, import_pdfnet_node.PDFNet.SDFDoc.SaveOptions.e_linearized);
      } catch (err) {
        console.error("Failure in PDFTron", err);
      }
    };
    const LICENSE_KEY = "xxxxx";
    await import_pdfnet_node.PDFNet.runWithCleanup(main, LICENSE_KEY);
    console.log("doc-generation ended");
    return { statusCode: 200, body: "success" };
  } catch (error) {
    return { statusCode: 500, body: error.message };
  }
};
//# sourceMappingURL=fill-word-template-apryse.js.map

1 Like

Please note that the NodeJS module is shim for our native SDK binary. Perhaps the issue is a failure to load PDFNet fully.

For a M1 Pro you would need to use our ARM64 macOS SDK, this download in particular.

https://nightly-pdftron-uploads.s3.us-west-1.amazonaws.com/stable/2023-11-02/10.5/pdfnet-node/PDFNetNode_MacArm64_Node18_2023-11-02_stable.zip

1 Like

Thank you Ryan.

I was able to get the pdfnet-node-samples working locally.

Internally at Apryse do you know if anyone has any local Lambda emulation setups working or within QA? It may very well be the serverless-offline program in terms of how it mimics API Gateway and Lambda creates some kind of mismatch with the node-addon lib (which appears to be what throws up in the stack).

I’d ideally be able to run tests locally before pushing to AWS but perhaps that might not be possible in my setup. Thanks.

1 Like

@Ryan -
Sorry to bug you but I’m trying to conduct my test on AWS now and I’m getting an error:

Failure in main Error: /opt/nodejs/node_modules/@pdftron/pdfnet-node/lib/addon.node: invalid ELF header
code: 'ERR_DLOPEN_FAILED'

I searched the forum and I do see another ticket where you mentioned its a binary issue.

What I’m trying to understand is how do I get a proper Lambda Layer working with PDFTron. Locally I have a Mac M1 machine and I was able to follow the downloading of the NodeJs pdfnet samples and can run that locally on my machine.

I took the node_modules folder within the samples project node_modules and put that into a zip file which I uploaded as a layer w/ architecture X86_64.

Our Lambdas are bundled using ESBuild so I marked @pdftron/pdfnet-node as an external and tied the layer to my lambda. I have the Lambda marked to use X86_64 as well along with 10240 of memory.

Note that I did try the same exercise with the Layer marked as ARM64 and the Lambda also marked as ARM64 but it did not seem to work.

Any assistance would be greatly appreciated.

Thanks,
Steve

1 Like

Certainly the error invalid ELF header means that the wrong binary is being loaded.

For both macOS and Linux we have x86_64 and arm64 binaries.

You need to make sure the correct binary is available at runtime.

e.g. if you develop on mac M1, but deploy to Linux ARM64, you still need to deploy the Linux ARM64 PDFNet binary, not the mac arm64 one.

1 Like

In terms of the steps to “deploy the… binary”. Its a node lambda so I’m referencing a node_modules path. Would I take my local pdfnet-node node_modules folder and then replace the lib folder contents with the binary to use on AWS?

Sorry if thats a dense question. When I tried to go to the Apryse Developer Portal page, the download button for Node just took me to the NPM page which I what I was using locally.

Thanks for your help. Hopefully I’m only a little guidance from getting this settled.

1 Like

Sorry, our users are using our products across all major OS/languages/frameworks, so I am not an expert in any single one.

Here are some other forum posts where other users resolved same/similar sounding issue. Hopefully one of these helps you out.

1 Like

@Ryan is it possible to send me a link to the prebuilt SDK binary for Linux ARM64 from the https://nightly-pdftron-uploads.s3.us-west-1.amazonaws.com/ site similar to what you sent above for the Mac OS? I’m not totally sure if I can build the Linux binary on my Mac without getting into using a Docker image so I figured I’d ask if PDF Tron already posts pre-built binaries for the different targets that I could just download directly and use for my Lambda layer.

1 Like

For any future folks looking at this ticket. If you’re like me and working on a local machine OS different from what your AWS target will be you can use the nightly build outputs (example here, Apryse Developer Portal) and find the target Zip that you need for your particular case.

Then depending on your bundling process you might include the node_modules folder with your Lambda bundle or you might be using Layers. I was using layers but you can take that Zip and use it as your source for your lambda layer. Then just make sure you have your compatible architectures properly configured on your lambda and layer to match the zip you used.

1 Like

Thank you for the note for your other fellow users.

Nightly builds are here:
https://dev.apryse.com/nightly

For example, latest 10.5 production ready builds are here:
https://dev.apryse.com/nightly/stable/2023-11-24/10.5

Latest ARM64 Linux here:
https://nightly-pdftron-uploads.s3.us-west-1.amazonaws.com/stable/2023-11-23/10.5/PDFNetCArm64_2023-11-23_stable.tar.gz

1 Like