{"record":{"id":"21b3d29f55ef5d40","repo":"pola-rs/polars","slug":"arctan2-expected-a-str-or-expr-got-a-quali","errorCode":null,"errorMessage":"`arctan2` expected a `str` or `Expr` got a `{qualified_type_name(x)}`","messagePattern":"`arctan2` expected a `str` or `Expr` got a `(.+?)`","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/functions/lazy.py","lineNumber":1760,"sourceCode":"    shape: (4, 3)\n    ┌───────────┬───────────┬───────────┐\n    │ y         ┆ x         ┆ atan2     │\n    │ ---       ┆ ---       ┆ ---       │\n    │ f64       ┆ f64       ┆ f64       │\n    ╞═══════════╪═══════════╪═══════════╡\n    │ 0.707107  ┆ 0.707107  ┆ 0.785398  │\n    │ -0.707107 ┆ 0.707107  ┆ -0.785398 │\n    │ 0.707107  ┆ -0.707107 ┆ 2.356194  │\n    │ -0.707107 ┆ -0.707107 ┆ -2.356194 │\n    └───────────┴───────────┴───────────┘\n    \"\"\"\n    if isinstance(y, str):\n        y = F.col(y)\n    if isinstance(x, str):\n        x = F.col(x)\n    if not hasattr(x, \"_pyexpr\"):\n        msg = f\"`arctan2` expected a `str` or `Expr` got a `{qualified_type_name(x)}`\"\n        raise TypeError(msg)\n    if not hasattr(y, \"_pyexpr\"):\n        msg = f\"`arctan2` expected a `str` or `Expr` got a `{qualified_type_name(y)}`\"\n        raise TypeError(msg)\n\n    return wrap_expr(plr.arctan2(y._pyexpr, x._pyexpr))\n\n\n@deprecated(\"`arctan2d` is deprecated; use `arctan2` followed by `.degrees()` instead.\")\ndef arctan2d(y: str | Expr, x: str | Expr) -> Expr:\n    \"\"\"\n    Compute two argument arctan in degrees.\n\n    .. deprecated:: 1.0.0\n        Use `arctan2` followed by :meth:`Expr.degrees` instead.\n\n    Returns the angle (in degrees) in the plane between the positive x-axis\n    and the ray from the origin to (x,y).\n","sourceCodeStart":1742,"sourceCodeEnd":1778,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/functions/lazy.py#L1742-L1778","documentation":"pl.arctan2(y, x) accepts only column names (str, converted to pl.col) or Expr for both arguments; validation duck-types on the _pyexpr attribute. A numeric literal, Series, or None in the x position fails the check and raises TypeError with its qualified type name. Constants must be wrapped in pl.lit.","triggerScenarios":"pl.arctan2(pl.col('y'), 2.0); pl.arctan2('y', some_series); pl.arctan2('y', None). Note the argument order is (y, x), so the x check fires second.","commonSituations":"Porting numpy arctan2(vec, 1.0) half-angle idioms; passing precomputed Series instead of columns; typos in the argument order causing the wrong operand to be the literal.","solutions":["Wrap constants: pl.arctan2(pl.col('y'), pl.lit(2.0))","Column names may stay as str; anything else must already be an Expr","For Series input, put the data in a frame and reference it by column name inside select"],"exampleFix":"# before\npl.arctan2(pl.col('y'), 2.0)  # TypeError on x\n\n# after\npl.arctan2(pl.col('y'), pl.lit(2.0))","handlingStrategy":"validation","validationCode":"def to_operand(v):\n    if isinstance(v, str):\n        return pl.col(v)\n    if not hasattr(v, '_pyexpr'):\n        return pl.lit(v)\n    return v\n\nexpr = pl.arctan2(to_operand(y), to_operand(x))","typeGuard":"def is_expr_or_str(v) -> bool:\n    return isinstance(v, (str, pl.Expr))","tryCatchPattern":null,"preventionTips":["In expression APIs every operand is an Expr — wrap constants with pl.lit","Type helper signatures as (y: str | Expr, x: str | Expr) and keep the (y, x) order explicit"],"tags":["polars","arctan2","expr","input-validation"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}