cocoindex-io/cocoindex · error · TypeError
expected {tp}{loc}, got {type(value).__name__}: {value!r}
Error message
expected {tp}{loc}, got {type(value).__name__}: {value!r} What it means
For a union annotation, TypeChecker tries each member's validator and only accepts the value if one succeeds. If every member raises TypeError, check_union raises a final TypeError naming the full union type, the value's runtime type, and a repr of the value, with an optional path suffix for nested positions.
Source
Thrown at python/cocoindex/_internal/datatype.py:321
return check_none
# Any — accept everything
if tp is Any:
return lambda _v, _p: None
# Union: str | int, str | None, etc.
if origin in (types.UnionType, typing.Union):
sub_fns = [_build_check_fn(a) for a in args]
def check_union(value: Any, path: str) -> None:
for fn in sub_fns:
try:
fn(value, path)
return
except TypeError:
continue
loc = f" at {path}" if path else ""
raise TypeError(
f"expected {tp}{loc}, got {type(value).__name__}: {value!r}"
)
return check_union
# Tuple types
if origin is tuple:
if len(args) == 2 and args[1] is Ellipsis:
# Variable-length: tuple[X, ...]
if args[0] is Any:
def check_var_tuple_any(value: Any, path: str) -> None:
if not isinstance(value, tuple):
loc = f" at {path}" if path else ""
raise TypeError(
f"expected tuple{loc}, got {type(value).__name__}"
)
View on GitHub (pinned to e84aa99b32)
Solutions
- Coerce the value to one of the union members before passing it (str(x), int(x))
- Widen the annotation to include the actual runtime type
- Fix the producer so it emits the declared type
Example fix
// before key = (table, 3.5) # annotated tuple[str, str | int] // after key = (table, str(3.5))
Defensive patterns
Strategy: validation
Validate before calling
def matches_union(v, members) -> bool:
return any(isinstance(v, m) for m in members) Type guard
def is_str_or_int(v: object) -> TypeGuard[str | int]:
return isinstance(v, (str, int)) Try / catch
try:
checker.check(value)
except TypeError as e:
logging.error("union mismatch: %s", e)
value = coerce(value) # str(value) or int(value) Prevention
- Coerce JSON/YAML-sourced scalars to declared types before passing
- Keep union annotations minimal; prefer a single concrete type when possible
- Include TypeChecker.check calls in input-validation tests
When it happens
Trigger: Passing a value that matches none of the union members — e.g. a key/argument annotated `str | int` receiving bytes, or `str | None` receiving a list — wherever TypeChecker validates stable keys or memo arguments.
Common situations: Config values read from JSON/yaml arriving as the wrong scalar type (e.g. int vs str); bytes-vs-str mixups; nested tuple element failing a `str | int` annotation (path like "[2]").
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- expected None{loc}, got {type(value).__name__}
- expected tuple{loc}, got {type(value).__name__}
- Context key '{key}': expected {t.__name__}, got {type(value)
- Invalid dtype specification: {dtype_spec}
- NDArray for Vector must use a concrete numpy dtype, got `Any
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/9150e99e1743aa31.
Report an issue: GitHub.