{"record":{"id":"06d40e08c83712b9","repo":"pathwaycom/pathway","slug":"cannot-change-type-from-right-to-left-ntable","errorCode":null,"errorMessage":"Cannot change type from {right} to {left}.\\nTable.update_types() should be used only for type narrowing or type extending.","messagePattern":"Cannot change type from (.+?) to (.+?)\\.\\\\nTable\\.update_types\\(\\) should be used only for type narrowing or type extending\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/pathway/internals/table.py","lineNumber":2247,"sourceCode":"\n    @trace_user_frame\n    @check_arg_types\n    def update_types(self, **kwargs: Any) -> Table:\n        \"\"\"Updates types in schema. Has no effect on the runtime.\"\"\"\n\n        for name in kwargs.keys():\n            if name not in self.keys():\n                raise ValueError(\n                    \"Table.update_types() argument name has to be an existing table column name.\"\n                )\n        new_schema = self.schema.with_types(**kwargs)\n        for name in kwargs.keys():\n            left = new_schema._dtypes()[name]\n            right = self.schema._dtypes()[name]\n            if not (\n                dt.dtype_issubclass(left, right) or dt.dtype_issubclass(right, left)\n            ):\n                raise TypeError(\n                    f\"Cannot change type from {right} to {left}.\\n\"\n                    + \"Table.update_types() should be used only for type narrowing or type extending.\"\n                )\n        return self._with_schema(new_schema)\n\n    @trace_user_frame\n    @check_arg_types\n    def update_id_type(self, id_type, *, id_append_only: bool | None = None) -> Table:\n        id_type = dt.wrap(id_type)\n        assert isinstance(id_type, dt.Pointer)\n        return self._with_schema(\n            self.schema.with_id_type(id_type, append_only=id_append_only)\n        )\n\n    @check_arg_types\n    def cast_to_types(self, **kwargs: Any) -> Table:\n        \"\"\"Casts columns to types.\"\"\"\n","sourceCodeStart":2229,"sourceCodeEnd":2265,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/internals/table.py#L2229-L2265","documentation":"Raised by Table.update_types() when the new type is neither a subtype nor a supertype of the current type for some column — i.e. the change is not a narrowing or widening. update_types only re-labels type hints without conversion, so unrelated types (e.g. int -> str) are rejected as would break the type lattice.","triggerScenarios":"t.update_types(col=str) when col is currently int; changing Pointer[int] to Pointer[str]; changing a column to a type with no subtype/supertype relation to the current one.","commonSituations":"Trying to 'convert' data with update_types instead of actually casting values; connector schema changed the declared type between environments; narrowing too aggressively after a widening elsewhere.","solutions":["To convert values, use cast_to_types (or pw.this.col.cast(...)) instead of update_types","To only re-hint within the hierarchy, pick a related type (subtype for narrowing, supertype for widening), e.g. int -> Any is allowed","Check the current dtype first: print(t.schema._dtypes()) or t.eval_type(pw.this.col)","If ids are involved, use update_id_type for Pointer types"],"exampleFix":"# before\nt2 = t.update_types(age=str)  # int -> str: not narrowing/widening -> TypeError\n\n# after (actual conversion)\nt2 = t.cast_to_types(age=str)\n# or a pure hint widening\nt2 = t.update_types(age=Any)","handlingStrategy":"type-guard","validationCode":"from pathway.internals import dtype as dt\n\ndef hint_compatible(old, new) -> bool:\n    old, new = dt.wrap(old), dt.wrap(new)\n    return dt.dtype_issubclass(new, old) or dt.dtype_issubclass(old, new)","typeGuard":"def is_narrowing_or_widening(t, col, new_type) -> bool:\n    from pathway.internals import dtype as dt\n    left, right = dt.wrap(new_type), t.schema._dtypes()[col]\n    return dt.dtype_issubclass(left, right) or dt.dtype_issubclass(right, left)","tryCatchPattern":"try:\n    t2 = t.update_types(col=str)\nexcept TypeError as e:\n    if 'should be used only for type narrowing' in str(e):\n        t2 = t.cast_to_types(col=str)","preventionTips":["Use cast_to_types for value conversion, update_types only for hint changes","Widen to Any when the hint must loosen","Check current dtype before choosing the new one"],"tags":["pathway","typing","update-types","type-cast"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}