Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.
This repository was archived by the owner on Jan 13, 2024. It is now read-only.

Recursive spawn of pkg binary fails #376

Closed

Description

@EricMCornelius

Minimal example:

$ cat index.js

const spawn = require('child_process').spawn;

if (process.argv[2] === 'run') {
  const proc = spawn('./testbin', ['test'], {stdio: 'inherit'});
}
else {
  console.log(process.argv);
}

$ pkg -o testbin -t latest-linux-x64 index.js

$ ./testbin run

module.js:542
    throw err;
    ^

Error: Cannot find module 'test'
    at Function.Module._resolveFilename (module.js:540:15)
    at Function.Module._resolveFilename (pkg/prelude/bootstrap.js:1269:46)
    at Function.Module._load (module.js:470:25)
    at Function.Module.runMain (pkg/prelude/bootstrap.js:1298:12)
    at startup (bootstrap_node.js:227:16)
    at bootstrap_node.js:649:3

Seems that this check in bootstrap.js is the culprit:

if (process.env.PKG_EXECPATH === EXECPATH) {
  process.argv.splice(1, 1);
} else {
  process.argv[1] = DEFAULT_ENTRYPOINT;
}

PKG_EXECPATH is being set as an environment variable transparently later on in the bootstrap shims:

function setOptsEnv (args) {
    var pos = args.length - 1;
    if (typeof args[pos] === 'function') pos -= 1;
    if (typeof args[pos] !== 'object' || Array.isArray(args[pos])) {
      pos += 1;
      args.splice(pos, 0, {});
    }
    var opts = args[pos];
    if (!opts.env) opts.env = require('util')._extend({}, process.env);
    if (opts.env.PKG_EXECPATH === 'PKG_INVOKE_NODEJS') return;
    opts.env.PKG_EXECPATH = EXECPATH;
  }

I'm not sure what the intention of deleting the entrypoint argument in the event of self-execution is - I'm sure there's a point that I'm missing.

Note that manually re-inserting the entrypoint as a command line argument works:

./testbin /assets/index.js run

However, the behavior seems odd. I'm working on a command line tool which orchestrates/coordinates commands (think ansible) - and self-invocation of the tool unexpectedly fails due to the above.

Activity

  1. jjhesk commented on Apr 30, 2018

    @jjhesk

    maybe this guy can help

  2. EricMCornelius commented on May 23, 2018

    @EricMCornelius
    Author

    @igorklopov - is there a reason for the process.argv.splice(1, 1); removal of a commandline argument when self-executing?

  3. tavisrudd commented on Jun 29, 2018

    @tavisrudd

    @igorklopov I'm also running into this bug when trying to upgrade from 4.2.6 on https://github.com/unbounce/iidy which invokes itself. Would you accept a PR that allows us to stop https://github.com/zeit/pkg/blob/20e6d00c5d679e2d29e49f6dfc5cea258cf7d71e/prelude/bootstrap.js#L1336 from passing PKG_EXECPATH through to child procs? Commenting that line out solves the issue for us.

  4. tavisrudd commented on Jun 29, 2018

    @tavisrudd

    FYI, I'm only noticing this bug on Linux. The same iidy tests that expose it run fine on macos.

  5. chanphillip commented on Aug 18, 2018

    @chanphillip

    I got the same issue. @tavisrudd 's solution works for my case too!

  6. divyenduz commented on Sep 17, 2018

    @divyenduz

    I am running into the same issue. Here is a minimal reproduction: https://github.com/divyenduz/pkg-npm-run

    Any known workarounds? :)

  7. matthieukern commented on Nov 26, 2018

    @matthieukern

    We encounter the issue on our side as well. Our workaround was (on Windows, but I think the same would work on other OS) to not directly run the process, but to wrap it with a cmd.exe that would overwrite the PKG_EXECPATH environment variable:

    exec(`cmd /V /C "set PKG_EXECPATH= && my_program.exe"`)
  8. Akkadius commented on Jul 2, 2019

    @Akkadius

    This took care of my issue as well

    I spent a few hours on this one, was completely bizarre

        if (process.platform === 'linux') {
          startProcessString = util.format(
            'PKG_EXECPATH=; ./bin/%s server-launcher %s &',
            path.basename(process.argv[0]),
            argString
          );
        }
    

    My actual error

    stderr: internal/modules/cjs/loader.js:582
        throw err;
        ^
    
    Error: Cannot find module '/home/eqemu/server/server-launcher'
        at Function.Module._resolveFilename (internal/modules/cjs/loader.js:580:15)
        at Function.Module._resolveFilename (pkg/prelude/bootstrap.js:1287:46)
        at Function.Module._load (internal/modules/cjs/loader.js:506:25)
        at Function.Module.runMain (pkg/prelude/bootstrap.js:1316:12)
        at startup (internal/bootstrap/node.js:320:19)
        at bootstrapNodeJSCore (internal/bootstrap/node.js:659:3)
    

    Nothing in my code does a require for server-launcher so I was sitting here trying to find some magical require statement where I was passing in something funky. This was incredibly elusive

    pkg 4.4
    node 10.16.0
    os Ubuntu 18.04 LTS

  9. edwardfoyle commented on Nov 24, 2020

    @edwardfoyle

    I was able to combine the suggestions of @matthieukern and @Akkadius into this fairly simple workaround using execa (I'm sure it can be done just using the native child_process as well):

    const winCallSelf = async args => {
      const { stdout, stderr } = await execa.command(`cmd /V /C "set PKG_EXECPATH= && ${process.argv[0]} ${args.join(' ')}"`, {
        stdio: 'inherit',
        shell: 'cmd.exe',
      });
      if (stderr) {
        throw new Error(stderr);
      }
      return stdout;
    };
    
    const nixCallSelf = async args => {
      const { stdout, stderr } = await execa.command(`PKG_EXECPATH=; ${process.argv[0]} ${args.join(' ')}`, {
        stdio: 'inherit',
        shell: 'bash',
      });
      if (stderr) {
        throw new Error(stderr);
      }
      return stdout;
    };
    
    module.exports = {
      callSelf: process.platform.startsWith('win') ? winCallSelf : nixCallSelf
    }
  10. github-actions commented on Apr 23, 2021

    @github-actions

    This issue is stale because it has been open 90 days with no activity. Remove the stale label or comment or this will be closed in 5 days. To ignore this issue entirely you can add the no-stale label

  11. github-actions commented on Apr 29, 2021

    @github-actions

    This issue is now closed due to inactivity, you can of course reopen or reference this issue if you see fit.

  12. hmakholm commented on May 4, 2021

    @hmakholm

    The intention must be to make

    spawn(process.execPath, "someOtherProgram.js", arg1, arg2, arg3)
    

    work the same way as it does in pure Node, where process.execPath points to Node.

    For what it's worth, it turns out the project I'm working on has code that depends on this -- though nobody on the team seems to have connected the dots before someone asked, "wait, how does this work at all", and it took some quite bemused debugging to figure out how pkg didn't break our program.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions