apache/beam · error · ValueError
Unexpected unbound parameter
Error message
Unexpected unbound parameter: %s
What it means
getcallargs_forhints binds a function's signature to its type hints; parameters with defaults that end up unbound are declared Any. If a parameter is still unbound after that — meaning signature.bind() should have caught it earlier — Beam raises ValueError('Unexpected unbound parameter') as an internal invariant check.
Solutions
- Restructure the callable so every parameter is bindable (avoid exotic POSITIONAL_ONLY + VAR_KEYWORD mixes in hinted functions)
- If decorating builtins, wrap them in a plain Python function with an explicit signature and hint that
- Ensure functools.wraps copies __wrapped__/__signature__ correctly or set __annotations__ explicitly
- File/upgrade against apache-beam if a normal Python signature triggers it — this is meant to be unreachable
Example fix
// before wrapper = functools.wraps(some_builtin)(fn) # builtin signature confuses binding // after def wrapper(*args, **kwargs): # explicit plain-Python signature with hints return some_builtin(*args, **kwargs)
Defensive patterns
Strategy: try-catch
Validate before calling
import inspect
def bindable(fn):
try:
inspect.signature(fn).bind(*[inspect.Parameter.empty]*len(inspect.signature(fn).parameters))
except TypeError:
return False
return True Type guard
def is_plain_python_callable(fn): return inspect.isfunction(fn) or inspect.ismethod(fn)
Try / catch
try:
bound = getcallargs_forhints(fn, hints)
except ValueError as e:
if 'Unexpected unbound parameter' in str(e):
bound = None # skip type checking for exotic signatures Prevention
- Wrap builtins/C functions in plain Python wrappers before hinting
- Keep hinted signatures simple (no exotic positional-only + **kwargs mixes)
- Set __annotations__ explicitly on decorators
When it happens
Trigger: A function whose signature.bind() behavior diverges from Beam's manual binding loop — typically signatures with POSITIONAL_ONLY/VAR_POSITIONAL/KEYWORD_ONLY mixes, functools.wraps of builtins (partial-builtins), or C functions where inspect semantics are unusual.
Common situations: Type-checking decorated builtins or C-extension callables; wrapping functions with functools.partial where the wrapper signature misreports parameters; Beam version regressions around new Python syntax (e.g. positional-only params in 3.8+).
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- According to type-hint expected
- All functions for a Combine PTransform must accept a single…
- Bad tuple arguments for
- Combiner input type must be specified positionally.
- Could not determine schema for type hints
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/97e9992350ee4a51.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/typehints/decorators.py:803
bound_args[param.name] = _normalize_var_positional_hint(
bound_args[param.name])
elif param.kind == param.VAR_KEYWORD:
bound_args[param.name] = _normalize_var_keyword_hint(
bound_args[param.name], param.name)
else:
# Unbound: must have a default or be variadic.
if param.annotation != param.empty:
bound_args[param.name] = param.annotation
elif param.kind == param.VAR_POSITIONAL:
bound_args[param.name] = _ANY_VAR_POSITIONAL
elif param.kind == param.VAR_KEYWORD:
bound_args[param.name] = _ANY_VAR_KEYWORD
elif param.default is not param.empty:
# Declare unbound parameters with defaults to be Any.
bound_args[param.name] = typehints.Any
else:
# This case should be caught by signature.bind() above.
raise ValueError('Unexpected unbound parameter: %s' % param.name)
return dict(bound_args)
def get_type_hints(fn: Any) -> IOTypeHints:
"""Gets the type hint associated with an arbitrary object fn.
Always returns a valid IOTypeHints object, creating one if necessary.
"""
# pylint: disable=protected-access
if not hasattr(fn, '_type_hints'):
try:
fn._type_hints = IOTypeHints.empty()
except (AttributeError, TypeError):
# Can't add arbitrary attributes to this object,
# but might have some restrictions anyways...
hints = IOTypeHints.empty()
return hintsView on GitHub (pinned to 12126d8942)