nodejs/node · error · TypeError

Attempt to merge dict value of type {v.__class__.__name__} i

Error message

Attempt to merge dict value of type {v.__class__.__name__} into incompatible type {to[k].__class__.__name__} for key {k}

What it means

MergeDicts checks type compatibility when a key already exists in the destination 'to'. str and int are mutually compatible (both treated as scalars); for any other pair the types must match exactly (isinstance(v, type(to[k]))). On mismatch it raises TypeError naming both types and the key.

Source

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

def MergeDicts(to, fro, to_file, fro_file):
    # I wanted to name the parameter "from" but it's a Python keyword...
    for k, v in fro.items():
        # It would be nice to do "if not k in to: to[k] = v" but that wouldn't give
        # copy semantics.  Something else may want to merge from the |fro| dict
        # later, and having the same dict ref pointed to twice in the tree isn't
        # what anyone wants considering that the dicts may subsequently be
        # modified.
        if k in to:
            bad_merge = False
            if type(v) in (str, int):
                if type(to[k]) not in (str, int):
                    bad_merge = True
            elif not isinstance(v, type(to[k])):
                bad_merge = True

            if bad_merge:
                raise TypeError(
                    "Attempt to merge dict value of type "
                    + v.__class__.__name__
                    + " into incompatible type "
                    + to[k].__class__.__name__
                    + " for key "
                    + k
                )
        if type(v) in (str, int):
            # Overwrite the existing value, if any.  Cheap and easy.
            is_path = IsPathSection(k)
            if is_path:
                to[k] = MakePathRelative(to_file, fro_file, v)
            else:
                to[k] = v
        elif isinstance(v, dict):
            # Recurse, guaranteeing copies will be made of objects that require it.
            if k not in to:
                to[k] = {}

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Make the two values the same type for key k (both scalar str/int, or both list, or both dict).
  2. Remove the conflicting value from one of the merging sources (include vs target vs configuration).
  3. Use list-policy suffixes (= ? +) intentionally for list keys instead of mixing types.
  4. Trace which MergeDicts call (settings propagation) introduces the conflicting value.

Example fix

// before: target has 'cflags': '-O2' but include merges 'cflags': ['-O2']
// after: use consistent list form in both: 'cflags': ['-O2']
Defensive patterns

Strategy: type-guard

Validate before calling

def compatible(a, b):
    if type(a) in (str, int) and type(b) in (str, int): return True
    return isinstance(a, type(b)) and isinstance(b, type(a))
for k, v in fro.items():
    if k in to and not compatible(to[k], v):
        raise TypeError('type clash on %s' % k)

Type guard

def types_compatible(a, b):
    if type(a) in (str,int) and type(b) in (str,int): return True
    return isinstance(a, type(b))

Try / catch

try:
    MergeDicts(to, fro, to_file, fro_file)
except TypeError as e:
    if 'incompatible type' in str(e): print('Align value types for the conflicting key'); raise

Prevention

When it happens

Trigger: Merging a dict where key k already exists in 'to' with value to[k], and the incoming v has an incompatible type — e.g. to[k] is a list but v is a str, or to[k] is a dict but v is an int.

Common situations: An include (.gypi) overriding a scalar with a list or vice-versa; a configuration base setting a dict where the target set a string; conflicting default vs platform-specific values; bad variable expansion changing a value's type.

Related errors


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