{"record":{"id":"a1ef8f7b52819071","repo":"nodejs/node","slug":"variable-expansion-in-this-context-permits-str-and","errorCode":null,"errorMessage":"Variable expansion in this context permits str and int only, found {cond_expr_expanded.__class__.__name__}","messagePattern":"Variable expansion in this context permits str and int only, found (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/gyp/input.py","lineNumber":1166,"sourceCode":"            i = i + 2\n        if result is None:\n            result = EvalSingleCondition(\n                cond_expr, true_dict, false_dict, phase, variables, build_file\n            )\n\n    return result\n\n\ndef EvalSingleCondition(cond_expr, true_dict, false_dict, phase, variables, build_file):\n    \"\"\"Returns true_dict if cond_expr evaluates to true, and false_dict\n    otherwise.\"\"\"\n    # Do expansions on the condition itself.  Since the condition can naturally\n    # contain variable references without needing to resort to GYP expansion\n    # syntax, this is of dubious value for variables, but someone might want to\n    # use a command expansion directly inside a condition.\n    cond_expr_expanded = ExpandVariables(cond_expr, phase, variables, build_file)\n    if type(cond_expr_expanded) not in (str, int):\n        raise ValueError(\n            \"Variable expansion in this context permits str and int \"\n            + \"only, found \"\n            + cond_expr_expanded.__class__.__name__\n        )\n\n    try:\n        if cond_expr_expanded in cached_conditions_asts:\n            ast_code = cached_conditions_asts[cond_expr_expanded]\n        else:\n            ast_code = compile(cond_expr_expanded, \"<string>\", \"eval\")\n            cached_conditions_asts[cond_expr_expanded] = ast_code\n        env = {\"__builtins__\": {}, \"v\": Version}\n        if eval(ast_code, env, variables):\n            return true_dict\n        return false_dict\n    except SyntaxError as e:\n        syntax_error = SyntaxError(\n            \"%s while evaluating condition '%s' in %s \"","sourceCodeStart":1148,"sourceCodeEnd":1184,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/gyp/input.py#L1148-L1184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rewrite the condition expression so it expands to a comparable string/int — e.g. compare against a scalar variable: ['<(my_flag) == \"1\"', {...}].","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).","Ensure the cond_expr is a Python expression string after expansion, not a bare list/dict."],"exampleFix":"// before — my_items is a list, expansion yields a list\n'conditions': [ ['<(my_items)', { 'defines': ['HAS_ITEMS'] }] ],\n// after — compare a scalar flag\n'conditions': [ ['<(use_items) == \"1\"', { 'defines': ['HAS_ITEMS'] }] ],","handlingStrategy":"type-guard","validationCode":"expanded = ExpandVariables(cond_expr, phase, variables, build_file)\nassert type(expanded) in (str, int), \\\n    f'Condition expression expanded to {type(expanded).__name__}; must be str or int'","typeGuard":"def expands_to_evaluable(cond_expr: str, variables: dict, phase) -> bool:\n    # heuristic: ensure no bare <@() list marker that would yield a list\n    return '<@' not in cond_expr and '>@' not in cond_expr and '^@' not in cond_expr","tryCatchPattern":null,"preventionTips":["Author condition expressions to evaluate to a boolean via scalar comparisons.","Never use the '@' (list) expansion marker inside a condition expression.","Confirm referenced variables resolve to scalars, not lists."],"tags":["gyp","conditions","type-check","expansion","build-config"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}