apache/beam · error · TypeCheckError

Unexpected VAR_KEYWORD value

Error message

Unexpected VAR_KEYWORD value: %s

What it means

_normalize_var_keyword_hint normalizes the hint for a **kwargs parameter into a Dict constraint. It requires a non-empty dict whose single entry maps the kwarg parameter name to a DictConstraint; any other form (None, empty dict, wrong key, non-DictConstraint value) raises TypeCheckError.

Solutions

  1. Store the hint as {arg_name: Dict[key_type, value_type]} so keys[0]==arg_name and the value is a DictConstraint
  2. Unwrap manually: if you have a bare DictConstraint, wrap it in a dict keyed by the kwargs parameter name
  3. Use the standard decorators (with_input_types / type annotations) rather than building hint structures by hand
  4. Log/inspect the failing hint dict and verify its single key matches the parameter name

Example fix

// before
hints.var_keyword_arg = Dict[str, Any]
// after
hints.var_keyword_arg = {'kwargs': Dict[str, Any]}
Defensive patterns

Strategy: validation

Validate before calling

def is_valid_var_keyword(h, name):
  return isinstance(h, dict) and list(h.keys()) == [name]

Try / catch

try:
  args = getcallargs_forhints(fn, hints)
except TypeCheckError as e:
  log.error('bad VAR_KEYWORD hint: %s', e)

Prevention

When it happens

Trigger: getcallargs_forhints on a function with **kwargs where the stored hint is not dict(kwargs=Dict[...]) — e.g. hint is a bare Dict[str, Any] (unwrapped), an empty dict, or keyed by a different name than arg_name.

Common situations: Hand-assembled IOTypeHints where the VAR_KEYWORD slot was set to a DictConstraint directly instead of the wrapper dict; serialized hints from a different Beam version; typos in the kwarg name key.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/7b4b43a7527c7414. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/typehints/decorators.py:747

  else:
    # Example: tuple(int, str) -> Tuple[Union[int, str], ...]
    return typehints.Tuple[typehints.Union[hint], ...]


def _normalize_var_keyword_hint(hint, arg_name):
  """Converts a var_keyword hint into Dict[<key type>, <value type>] form.

  Args:
    hint: (dict) Should either contain a pair (arg_name,
      Dict[<key type>, <value type>]), or one or more possible types for the
      value.
    arg_name: (str) The keyword receiving this hint.

  Raises:
    TypeCheckError if hint does not have the right form.
  """
  if not hint or type(hint) != dict:
    raise TypeCheckError('Unexpected VAR_KEYWORD value: %s' % hint)
  keys = list(hint.keys())
  values = list(hint.values())
  if (len(values) == 1 and keys[0] == arg_name and
      isinstance(values[0], typehints.DictConstraint)):
    # Example: dict(kwargs=Dict[str, Any]) -> Dict[str, Any]
    return values[0]
  else:
    # Example: dict(k1=str, k2=int) -> Dict[str, Union[str,int]]
    return typehints.Dict[str, typehints.Union[values]]


def getcallargs_forhints(func, *type_args, **type_kwargs):
  """Bind type_args and type_kwargs to func.

  Works like inspect.getcallargs, with some modifications to support type hint
  checks.
  For unbound args, will use annotations and fall back to Any (or variants of
  Any).

View on GitHub (pinned to 12126d8942)