{"record":{"id":"cd9ff6dceeb3c0b9","repo":"xai-org/x-algorithm","slug":"tuple-ty-has-different-number-of-arguments-from","errorCode":null,"errorMessage":"Tuple {ty} has different number of arguments from given value {vals}","messagePattern":"Tuple (.+?) has different number of arguments from given value (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"phoenix/python/common/xai-configlib/src/xai_configlib/__init__.py","lineNumber":425,"sourceCode":"        raise ValueError(f\"Expected bool [True, true, False, false], got {val!r}\")\n    elif is_optional(ty) and val == \"None\":\n        return None\n    elif is_union(ty):\n        subtys = [subty for subty in get_args(ty) if subty is not type(None)]\n        for subty in subtys:\n            try:\n                return cast_type(subty, val)\n            except ValueError:\n                if subty is subtys[-1]:\n                    raise\n        raise TypeError(f\"Got {val} for union type {ty}\")\n    elif is_tuple(ty):\n        if not val:\n            return ()\n        vals = val.split(\",\")\n        tys = get_args(ty)\n        if len(vals) != len(tys):\n            raise TypeError(f\"Tuple {ty} has different number of arguments from given value {vals}\")\n        return tuple(cast_type(a_ty, v) for a_ty, v in zip(tys, vals))\n    elif is_list(ty):\n        if not val:\n            return []\n        vals = val.split(\",\")\n        tys = get_args(ty)\n        return [cast_type(tys[0], x) for x in vals]\n    elif is_dict(ty):\n        kty, vty = get_args(ty)\n        result = {}\n        for item in val.split(\",\"):\n            k, v = item.split(\":\", 1)\n            result[cast_type(kty, k.strip())] = cast_type(vty, v.strip())\n        return result\n    elif is_path(ty):\n        return Path(val)\n    elif is_bytes(ty):\n        return base64.b64decode(val.encode(\"utf-8\"))","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/phoenix/python/common/xai-configlib/src/xai_configlib/__init__.py#L407-L443","documentation":"For tuple-typed fields, cast_type splits the string on ',' and requires the number of parts to equal the number of type args in the Tuple annotation. A mismatch raises this TypeError.","triggerScenarios":"Overriding a Tuple[int, int] field with '256' (one value) or '1,2,3' (three values); also passing a value with a trailing comma creating an empty element.","commonSituations":"Changing a tuple field's arity in the config but not the CLI override, or copying an override from a config with a different tuple size.","solutions":["Count the Tuple type args and supply exactly that many comma-separated values","Update the override after changing the field's tuple arity in the dataclass"],"exampleFix":"# before\nreplace_cli_subs(cfg, [\"image_size=256\"])  # field: Tuple[int, int]\n# after\nreplace_cli_subs(cfg, [\"image_size=256,256\"])","handlingStrategy":"validation","validationCode":"from typing import get_args, get_origin\n\ndef tuple_arity_ok(ty, val: str) -> bool:\n    if get_origin(ty) is not tuple:\n        return True\n    return len(val.split(\",\")) == len(get_args(ty))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep CLI tuple overrides in sync with the annotation arity","Add a unit test asserting overrides parse for every config field"],"tags":["config","type-coercion","tuple","validation"],"backgroundTag":"type-coercion-failed","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}