nodejs/node · error · GypError

Unknown command string '%s' in '%s'.

Error message

Unknown command string '%s' in '%s'.

What it means

Inside a <! or >! command expansion, GYP recognizes an optional command_string prefix that selects how the command is dispatched. The only supported command_string is 'pymod_do_main'; any other recognized-but-unsupported command_string value raises this GypError listing both the unknown command and the raw contents. This is a parser-level rejection, not a runtime failure of the command itself.

Source

Thrown at tools/gyp/pylib/gyp/input.py:953

                    sys.path.append(os.getcwd())
                    try:
                        parsed_contents = shlex.split(contents)
                        try:
                            py_module = __import__(parsed_contents[0])
                        except ImportError as e:
                            raise GypError(
                                "Error importing pymod_do_main"
                                "module (%s): %s" % (parsed_contents[0], e)
                            )
                        replacement = str(
                            py_module.DoMain(parsed_contents[1:])
                        ).rstrip()
                    finally:
                        sys.path.pop()
                        os.chdir(oldwd)
                    assert replacement is not None
                elif command_string:
                    raise GypError(
                        "Unknown command string '%s' in '%s'."
                        % (command_string, contents)
                    )
                else:
                    # Fix up command with platform specific workarounds.
                    contents = FixupPlatformCommand(contents)
                    try:
                        # stderr will be printed no matter what
                        result = subprocess.run(
                            contents,
                            stdout=subprocess.PIPE,
                            shell=use_shell,
                            cwd=build_file_dir,
                            check=False,
                        )
                    except Exception as e:
                        raise GypError(
                            "%s while executing command '%s' in %s"

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Remove the unsupported prefix and write the command as a plain shell command '<!(my_cmd args)' instead of '<!(prefix args)'.
  2. If you wanted Python, switch to the supported '<!(pymod_do_main module args)' form and expose DoMain in the module.
  3. Inspect the regex match in the GypError's 'contents' to see exactly what GYP parsed as command_string vs. contents, then fix the expression accordingly.

Example fix

// before — 'sh' is not a supported command_string
'value': '<!(sh gen_version.sh)',
// after — run the shell script directly
'value': '<!(sh gen_version.sh)',  # i.e. drop any 'command_string:' prefix the regex mistook; if you had '<!pymod_do_main:...' remove the colon form
// correct pymod form:
'value': '<!(pymod_do_main version_helper)',
Defensive patterns

Strategy: validation

Validate before calling

supported = {'pymod_do_main'}
assert command_string in supported or command_string == '', \
    f'Unsupported GYP command_string {command_string!r}; use pymod_do_main or a plain shell command'

Type guard

def is_supported_command_string(cmd: str) -> bool:
    return cmd in ('', 'pymod_do_main')

Prevention

When it happens

Trigger: A .gyp file writes something like '<!(myCmd args)' where 'myCmd' is parsed by GYP's regex as a command_string rather than a plain shell command, or the user assumes GYP supports other prefixed commands. Effectively any command_string that isn't 'pymod_do_main' and isn't empty reaches this branch.

Common situations: Misreading the GYP docs and inventing a command_string prefix; a stray token before the paren that the regex latches onto as a command_string; copy-paste from a non-GYP build system that uses a different prefix syntax.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/644f1d49515b7324. Report an issue: GitHub.