nodejs/node · error · ValueError
Dictionary key is not a string.
Error message
Dictionary key is not a string.
What it means
ValueError raised by GenerateTokens in gypi_to_gn.py when a dict key is not a Python str. GN identifiers must be string tokens, so any int/bool/None key from the GYP data is rejected before emission. This guard runs before the GN-identifier-validity check.
Source
Thrown at tools/gypi_to_gn.py:149
elif isinstance(v, int):
yield str(v)
elif isinstance(v, list):
yield '['
for i, item in enumerate(v):
if i > 0:
yield ','
for tok in GenerateTokens(item, level + 1):
yield tok
yield ']'
elif isinstance(v, dict):
if level > 0:
yield '{'
for key in sorted(v):
if not isinstance(key, str):
raise ValueError('Dictionary key is not a string.')
if not key or key[0].isdigit() or not key.replace('_', '').isalnum():
raise ValueError('Dictionary key is not a valid GN identifier.')
yield key # No quotations.
yield '='
for tok in GenerateTokens(v[key], level + 1):
yield tok
if level > 0:
yield '}'
else: # Not supporting float: Add only when needed.
raise ValueError('Unsupported type when printing to GN.')
can_start = lambda tok: tok and tok not in ',}]='
can_end = lambda tok: tok and tok not in ',{[='
# Adds whitespaces, trying to keep everything (except dicts) in 1 line.
def PlainGlue(gen):
prev_tok = NoneView on GitHub (pinned to 1b2de5e052)
Solutions
- Coerce all dict keys to str before passing the structure to GenerateTokens.
- Fix the upstream producer so it emits string keys.
- Sanitize the loaded GYP data with a recursive key-stringification pass.
Example fix
# before
data = {1: 'x', 'foo': 'y'}
tokens = list(GenerateTokens(data))
# after
def stringify_keys(o):
if isinstance(o, dict):
return {str(k): stringify_keys(v) for k, v in o.items()}
if isinstance(o, list):
return [stringify_keys(i) for i in o]
return o
tokens = list(GenerateTokens(stringify_keys(data))) Defensive patterns
Strategy: type-guard
Validate before calling
def all_keys_str(obj) -> bool:
if isinstance(obj, dict):
return all(isinstance(k, str) and all_keys_str(v) for k, v in obj.items())
if isinstance(obj, list):
return all(all_keys_str(i) for i in obj)
return True Type guard
def has_only_string_keys(d: dict) -> bool:
return all(isinstance(k, str) for k in d) Try / catch
try:
list(GenerateTokens(data))
except ValueError as e:
if 'not a string' in str(e):
data = stringify_keys(data) # coerce and retry Prevention
- Coerce dict keys to str when loading from JSON/YAML.
- Sanitize GYP data with a recursive transform before conversion.
- Avoid building dicts with numeric keys programmatically.
When it happens
Trigger: Calling GenerateTokens on a dict whose keys include non-string types - typically the result of JSON parsing with numeric keys, or GYP data transformed by code that converted keys to ints.
Common situations: GYP inputs that were round-tripped through JSON or YAML with int keys, or programmatically built dicts using enumerate()/indices as keys.
Related errors
- Unsupported type when printing to GN.
- --depfile requires --stamp and vice versa
- --depfile requires --stamp and vice versa
- Dictionary key is not a valid GN identifier.
- Invalid config specified via --build: %s
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/2470de582f07b1d9.
Report an issue: GitHub.