{"record":{"id":"6bf95ccd7c6c53d6","repo":"pathwaycom/pathway","slug":"cannot-change-type-from-right-to-left-npw-de","errorCode":null,"errorMessage":"Cannot change type from {right} to {left}.\\npw.`declare_type` should be used only for type narrowing or type extending.","messagePattern":"Cannot change type from (.+?) to (.+?)\\.\\\\npw\\.`declare_type` should be used only for type narrowing or type extending\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/pathway/internals/type_interpreter.py","lineNumber":366,"sourceCode":"\n        if not expression._unwrap and (\n            isinstance(default_type, dt.Optional) or default_type == dt.NONE\n        ):\n            target_type = dt.Optional(target_type)\n\n        return _wrap(expression, target_type)\n\n    def eval_declare(\n        self,\n        expression: expr.DeclareTypeExpression,\n        state: TypeInterpreterState | None = None,\n        **kwargs,\n    ) -> expr.DeclareTypeExpression:\n        expression = super().eval_declare(expression, state=state, **kwargs)\n        left = expression._return_type\n        right = expression._expr._dtype\n        if not (dt.dtype_issubclass(left, right) or dt.dtype_issubclass(right, left)):\n            raise TypeError(\n                f\"Cannot change type from {right} to {left}.\\n\"\n                + \"pw.`declare_type` should be used only for type narrowing or type extending.\"\n            )\n        return _wrap(expression, expression._return_type)\n\n    def eval_coalesce(\n        self,\n        expression: expr.CoalesceExpression,\n        state: TypeInterpreterState | None = None,\n        **kwargs,\n    ) -> expr.CoalesceExpression:\n        expression = super().eval_coalesce(expression, state=state, **kwargs)\n        dtypes = [arg._dtype for arg in expression._args]\n        self._check_for_disallowed_types(\"pathway.coalesce\", *dtypes)\n        ret_type = dtypes[0]\n        non_optional_arg = False\n        for dtype in dtypes:\n            try:","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/internals/type_interpreter.py#L348-L384","documentation":"Raised by the type interpreter for pw.declare_type expressions. declare_type may only narrow (declared subtype of actual) or widen (actual subtype of declared) a column's type; if the two dtypes are unrelated, Pathway refuses the cast because it would not be a sound up/down-cast and could hide real type errors.","triggerScenarios":"pw.declare_type(str, pw.this.int_col) where int_col is int (unrelated types); declaring a column as DateTime when it is currently str without going through proper parsing (pw.utc); narrowing pw.Json to a wrong concrete type direction.","commonSituations":"Trying to use declare_type as a generic cast replacement for astype/cast_to; connector schemas that infer str while the user wants DateTime directly; porting pandas astype calls.","solutions":["For genuine conversion (e.g. str to DateTime) use parsing functions: pw.this.col.strptime(...) / pw.utc or astype/cast_to instead of declare_type","For narrowing, make sure the declared type is a subtype of the current one (e.g. Any -> int)","For widening, declare a supertype of the current dtype","If types are truly unrelated, insert an explicit conversion expression first, then declare_type if still needed"],"exampleFix":"# before\nv = pw.declare_type(datetime, pw.this.ts)  # pw.this.ts is str -> unrelated, raises\n\n# after\nv = pw.this.ts.dt.strptime(\"%Y-%m-%d %H:%M:%S\")  # real conversion","handlingStrategy":"type-guard","validationCode":"import pathway as pw\n\ndef declare_is_sound(declared, actual) -> bool:\n    return (\n        declared.equivalent_to(actual)\n        or pw.typehints.issubtype(declared, actual)\n        or pw.typehints.issubtype(actual, declared)\n    )","typeGuard":"def declare_is_sound(declared, actual) -> bool:\n    import pathway as pw\n    return pw.typehints.issubtype(declared, actual) or pw.typehints.issubtype(actual, declared)","tryCatchPattern":"try:\n    v = pw.declare_type(T, pw.this.col)\nexcept TypeError:\n    v = pw.this.col.astype(T)  # real conversion instead of declaration","preventionTips":["Use declare_type only for narrowing Any or widening to a supertype","For real conversions use astype / strptime / pw.utc parsing functions","Review every declare_type call in code review: is it up- or down-cast?"],"tags":["pathway","type-checking","declare-type","dtype","typeerror"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}