nodejs/node · error · ValueError

Variable expansion in this context permits str and int only,

Error message

Variable expansion in this context permits str and int only, found {cond_expr_expanded.__class__.__name__}

What it means

Before evaluating a condition expression via Python eval, EvalSingleCondition runs ExpandVariables on the cond_expr and requires the result to be a str or int (the only types compile/eval can meaningfully handle). If expansion produced a list, dict, or other type, GYP raises this ValueError naming the offending class. This protects the subsequent compile() and eval() from receiving an un-evaluatable object.

Source

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

            i = i + 2
        if result is None:
            result = EvalSingleCondition(
                cond_expr, true_dict, false_dict, phase, variables, build_file
            )

    return result


def EvalSingleCondition(cond_expr, true_dict, false_dict, phase, variables, build_file):
    """Returns true_dict if cond_expr evaluates to true, and false_dict
    otherwise."""
    # Do expansions on the condition itself.  Since the condition can naturally
    # contain variable references without needing to resort to GYP expansion
    # syntax, this is of dubious value for variables, but someone might want to
    # use a command expansion directly inside a condition.
    cond_expr_expanded = ExpandVariables(cond_expr, phase, variables, build_file)
    if type(cond_expr_expanded) not in (str, int):
        raise ValueError(
            "Variable expansion in this context permits str and int "
            + "only, found "
            + cond_expr_expanded.__class__.__name__
        )

    try:
        if cond_expr_expanded in cached_conditions_asts:
            ast_code = cached_conditions_asts[cond_expr_expanded]
        else:
            ast_code = compile(cond_expr_expanded, "<string>", "eval")
            cached_conditions_asts[cond_expr_expanded] = ast_code
        env = {"__builtins__": {}, "v": Version}
        if eval(ast_code, env, variables):
            return true_dict
        return false_dict
    except SyntaxError as e:
        syntax_error = SyntaxError(
            "%s while evaluating condition '%s' in %s "

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Rewrite the condition expression so it expands to a comparable string/int — e.g. compare against a scalar variable: ['<(my_flag) == "1"', {...}].
  2. If the variable is a list, wrap the comparison in a form that yields a scalar (e.g. count via a <!pymod_do_main helper).
  3. Ensure the cond_expr is a Python expression string after expansion, not a bare list/dict.

Example fix

// before — my_items is a list, expansion yields a list
'conditions': [ ['<(my_items)', { 'defines': ['HAS_ITEMS'] }] ],
// after — compare a scalar flag
'conditions': [ ['<(use_items) == "1"', { 'defines': ['HAS_ITEMS'] }] ],
Defensive patterns

Strategy: type-guard

Validate before calling

expanded = ExpandVariables(cond_expr, phase, variables, build_file)
assert type(expanded) in (str, int), \
    f'Condition expression expanded to {type(expanded).__name__}; must be str or int'

Type guard

def expands_to_evaluable(cond_expr: str, variables: dict, phase) -> bool:
    # heuristic: ensure no bare <@() list marker that would yield a list
    return '<@' not in cond_expr and '>@' not in cond_expr and '^@' not in cond_expr

Prevention

When it happens

Trigger: A condition expression that is itself a <(var) reference resolving to a list (e.g. '<(my_list)' where my_list is a list); a condition whose expansion yields a dict; programmatic gyp usage setting the cond_expr to a non-string.

Common situations: Accidentally using a list-valued variable as the entirety of a condition expression; expecting expansion to join a list into a string (it does not in this context); copy-pasting an expansion that yields a list where a boolean expression string was intended.

Related errors


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