nodejs/node · error · GypError

%s %s must be at least length 2, not %s

Error message

%s %s must be at least length 2, not %s

What it means

Each condition entry must have at least two elements — a cond_expr and a true_dict — so that EvalCondition can index condition[0] and condition[1]. If len(condition) < 2 (e.g. an empty list or a lone expression with no body), GYP raises this GypError, embedding the (possibly empty) condition[0] and the actual length. Note the code comment: if condition[0] itself raises IndexError on an empty list, that bubbles up — also a sign of the same root cause.

Source

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

        output = int(output)

    return output


# The same condition is often evaluated over and over again so it
# makes sense to cache as much as possible between evaluations.
cached_conditions_asts = {}


def EvalCondition(condition, conditions_key, phase, variables, build_file):
    """Returns the dict that should be used or None if the result was
    that nothing should be used."""
    if not isinstance(condition, list):
        raise GypError(conditions_key + " must be a list")
    if len(condition) < 2:
        # It's possible that condition[0] won't work in which case this
        # attempt will raise its own IndexError.  That's probably fine.
        raise GypError(
            conditions_key
            + " "
            + condition[0]
            + " must be at least length 2, not "
            + str(len(condition))
        )

    i = 0
    result = None
    while i < len(condition):
        cond_expr = condition[i]
        true_dict = condition[i + 1]
        if not isinstance(true_dict, dict):
            raise GypError(
                f"{conditions_key} {cond_expr} must be followed by a dictionary, "
                f"not {type(true_dict)}"
            )
        if len(condition) > i + 2 and isinstance(condition[i + 2], dict):

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Add the required second element — a dict merged in when the condition is true.
  2. If the condition is intentionally a no-op, remove the whole entry rather than leaving a 1-element list.
  3. Optionally add a third dict (false_dict) for the else branch.

Example fix

// before
'conditions': [ ['OS == "mac"'] ],
// after
'conditions': [ ['OS == "mac"', { 'defines': ['IS_MAC'] }] ],
Defensive patterns

Strategy: validation

Validate before calling

def validate_condition(entry, key='conditions'):
    assert isinstance(entry, list) and len(entry) >= 2, \
        f'{key} entry {entry!r} must have at least [expr, true_dict]'

Type guard

def has_min_length_two(entry) -> bool:
    return isinstance(entry, list) and len(entry) >= 2

Prevention

When it happens

Trigger: Writing "'conditions': [ ['OS==\"mac\"'] ]" with no dict body; an empty condition list "'conditions': [ [] ]"; a generator that emits only the expression half.

Common situations: Truncated copy-paste of a condition; deleting the true_dict during editing and forgetting to restore it; templating that drops the body when a variable is empty.

Related errors


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