xai-org/x-algorithm · error · TypeError

Got {val} for union type {ty}

Error message

Got {val} for union type {ty}

What it means

When the target type is a Union, cast_type tries each member type in order and re-raises if the last one fails, then also raises this TypeError as a fallback when no member could parse the value.

Source

Thrown at phoenix/python/common/xai-configlib/src/xai_configlib/__init__.py:418

def cast_type(ty: Type[Any], val: str):
    if ty is bool:
        if val in ("False", "false"):
            return False
        elif val in ("True", "true"):
            return True
        raise ValueError(f"Expected bool [True, true, False, false], got {val!r}")
    elif is_optional(ty) and val == "None":
        return None
    elif is_union(ty):
        subtys = [subty for subty in get_args(ty) if subty is not type(None)]
        for subty in subtys:
            try:
                return cast_type(subty, val)
            except ValueError:
                if subty is subtys[-1]:
                    raise
        raise TypeError(f"Got {val} for union type {ty}")
    elif is_tuple(ty):
        if not val:
            return ()
        vals = val.split(",")
        tys = get_args(ty)
        if len(vals) != len(tys):
            raise TypeError(f"Tuple {ty} has different number of arguments from given value {vals}")
        return tuple(cast_type(a_ty, v) for a_ty, v in zip(tys, vals))
    elif is_list(ty):
        if not val:
            return []
        vals = val.split(",")
        tys = get_args(ty)
        return [cast_type(tys[0], x) for x in vals]
    elif is_dict(ty):
        kty, vty = get_args(ty)
        result = {}
        for item in val.split(","):

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Check the field's Union annotation and supply a value matching one member exactly
  2. Wrap in Optional and pass 'None' if you want null
  3. Fix the value's format (e.g. correct tuple arity '1,2')

Example fix

# before
replace_cli_subs(cfg, ["crop=1,2,3"])  # field: Union[int, Tuple[int, int]]
# after
replace_cli_subs(cfg, ["crop=1,2"])
Defensive patterns

Strategy: validation

Validate before calling

from typing import get_args, get_origin, Union, TypeAliasType

def union_accepts(ty, val: str) -> bool:
    origin = get_origin(ty)
    if origin is not Union:
        return True
    from xai_configlib import cast_type
    return any(
        (lambda ok: ok)(False) if s is type(None) else _try(cast_type, s, val)
        for s in get_args(ty)
    )
def _try(f, *a):
    try: f(*a); return True
    except (ValueError, TypeError): return False

Try / catch

try:
    cast_type(field_ty, raw)
except (ValueError, TypeError) as e:
    print(f"Override for {field_name} rejected: {e}")

Prevention

When it happens

Trigger: Overriding a field annotated e.g. Optional[int] or Union[int, str-list] with a string that matches none of the member types (note 'None' is handled only at the Optional level, so Union[int, str] with a weird value, or a Union of containers with mismatched element counts).

Common situations: Passing a comma list to Union[int, Tuple[int,int]] with wrong arity, or expecting implicit string-to-float conversion in a Union that lacks float.

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/b137b12d4802d312. Report an issue: GitHub.