{"record":{"id":"6ee27e2c3142d979","repo":"pola-rs/polars","slug":"require-half-life-0-found-half-life-r","errorCode":null,"errorMessage":"require `half_life` > 0 (found {half_life!r})","messagePattern":"require `half_life` > 0 \\(found (.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/expr/expr.py","lineNumber":12809,"sourceCode":"            \"parameters `com`, `span`, `half_life`, and `alpha` are mutually exclusive\"\n        )\n        raise ValueError(msg)\n    if com is not None:\n        if com < 0.0:\n            msg = f\"require `com` >= 0 (found {com!r})\"\n            raise ValueError(msg)\n        alpha = 1.0 / (1.0 + com)\n\n    elif span is not None:\n        if span < 1.0:\n            msg = f\"require `span` >= 1 (found {span!r})\"\n            raise ValueError(msg)\n        alpha = 2.0 / (span + 1.0)\n\n    elif half_life is not None:\n        if half_life <= 0.0:\n            msg = f\"require `half_life` > 0 (found {half_life!r})\"\n            raise ValueError(msg)\n        alpha = 1.0 - math.exp(-math.log(2.0) / half_life)\n\n    elif alpha is None:\n        msg = \"one of `com`, `span`, `half_life`, or `alpha` must be set\"\n        raise ValueError(msg)\n\n    elif not (0 < alpha <= 1):\n        msg = f\"require 0 < `alpha` <= 1 (found {alpha!r})\"\n        raise ValueError(msg)\n\n    return alpha\n\n\ndef _prepare_rolling_by_window_args(window_size: timedelta | str) -> str:\n    if isinstance(window_size, timedelta):\n        window_size = parse_as_duration_string(window_size)\n    return window_size\n","sourceCodeStart":12791,"sourceCodeEnd":12827,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/expr/expr.py#L12791-L12827","documentation":"_prepare_alpha requires half_life > 0 (strictly positive): half_life maps to alpha = 1 - exp(-ln2/half_life), and zero or negative half_life makes the formula undefined or degenerate. Unlike span, even the boundary value 0 is rejected.","triggerScenarios":"pl.col('x').ewm_mean(half_life=0) or half_life=-3; also pandas-style ewm(halflife=...) ports where a zero default slipped through.","commonSituations":"half_life computed from data or time deltas that can be zero (e.g. elapsed time of zero); config defaults set to 0 meaning 'disabled' but forwarded anyway; unit confusion (half-life in days passed as 0 for 'same day').","solutions":["Pass a strictly positive half_life, e.g. ewm_mean(half_life=2.0).","If 0 means 'no smoothing' in your config, translate it to alpha=1 or skip the EWM call.","Validate data-derived half_lives at the point of computation, not inside the query."],"exampleFix":"# before\npl.col('x').ewm_mean(half_life=0)\n\n# after\npl.col('x').ewm_mean(half_life=2.0)","handlingStrategy":"validation","validationCode":"if half_life is not None:\n    assert half_life > 0, f'half_life must be > 0, got {half_life!r}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["half_life must be strictly positive — 0 is invalid, unlike span where 1 is allowed.","Never use 0 as a sentinel for 'off' and still call the EWM API."],"tags":["validation","polars","expression","ewm","statistics"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}