{"record":{"id":"292d1afd18bdbc87","repo":"pathwaycom/pathway","slug":"expression-r-can-only-be-applied-to-json-columns","errorCode":null,"errorMessage":"{expression!r} can only be applied to JSON columns, but column has type {expression._expr._dtype.typehint}.","messagePattern":"(.+?) can only be applied to JSON columns, but column has type (.+?)\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/pathway/internals/type_interpreter.py","lineNumber":336,"sourceCode":"        expression: expr.CastExpression,\n        state: TypeInterpreterState | None = None,\n        **kwargs,\n    ) -> expr.CastExpression:\n        expression = super().eval_cast(expression, state=state, **kwargs)\n        return _wrap(expression, expression._return_type)\n\n    def eval_convert(\n        self,\n        expression: expr.ConvertExpression,\n        state: TypeInterpreterState | None = None,\n        **kwargs,\n    ) -> expr.ConvertExpression:\n        expression = super().eval_convert(expression, state=state, **kwargs)\n        target_type = expression._return_type\n        default_type = expression._default._dtype\n\n        if dt.unoptionalize(expression._expr._dtype) is not dt.JSON:\n            raise TypeError(\n                f\"{expression!r} can only be applied to JSON columns, \"\n                f\"but column has type {expression._expr._dtype.typehint}.\"\n            )\n\n        if default_type != dt.NONE and not dt.dtype_issubclass(\n            dt.unoptionalize(default_type), target_type\n        ):\n            raise TypeError(\n                f\"type of default {default_type.typehint} \"\n                f\"is not compatible with {target_type.typehint}.\"\n            )\n\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)","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/internals/type_interpreter.py#L318-L354","documentation":"Raised by the type interpreter for a ConvertExpression (pw.unwrap) applied to a column whose dtype is not Json (after unoptionalize). unwrap() converts JSON-typed values into concrete Python values; using it on str, int, or any non-Json column is a type error detected at graph construction.","triggerScenarios":"pw.this.col.unwrap() where col was typed as str/float/Any instead of Json; unwrapping a column produced by a connector with a plain schema; calling unwrap on the result of get() whose type is already concrete after conversion.","commonSituations":"JSON payloads ingested with a schema that declares fields as str instead of Json; forgetting that pw.json parses into Json dtype and applying unwrap twice; columns that were already cast away from Json earlier in the pipeline.","solutions":["Declare the column as Json in the schema (value: pw.Json) so unwrap() is valid","Remove the unwrap() call if the column already has a concrete type — it is only for Json columns","If the column is Any, cast to Json first (pw.cast_to(pw.Json)) then unwrap"],"exampleFix":"# before\nclass Input(pw.Schema):\n    payload: str  # actually holds JSON\nout = table.select(v=pw.this.payload.unwrap())  # TypeError: not a JSON column\n\n# after\nclass Input(pw.Schema):\n    payload: pw.Json\nout = table.select(v=pw.this.payload.unwrap())","handlingStrategy":"type-guard","validationCode":"import pathway as pw\n\ndef is_json_column(dtype) -> bool:\n    return dtype.equivalent_to(pw.typehints.Json()) or dtype.unoptionalize().equivalent_to(pw.typehints.Json())\n\n# only call unwrap when True","typeGuard":"def is_json_column(dtype) -> bool:\n    import pathway as pw\n    th = dtype.unoptionalize() if hasattr(dtype, \"unoptionalize\") else dtype\n    return th.equivalent_to(pw.typehints.Json())","tryCatchPattern":"try:\n    out = t.select(v=pw.this.col.unwrap())\nexcept TypeError:\n    out = t.select(v=pw.this.col)  # column already concrete; skip unwrap","preventionTips":["Type JSON payload fields as pw.Json in schemas from day one","Remember unwrap is only for Json columns; concrete columns need no unwrap","Keep a project-wide convention: parse (pw.json) -> unwrap -> use"],"tags":["pathway","type-checking","unwrap","json","typeerror"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}