{"record":{"id":"50a722ebf474f7a7","repo":"jax-ml/jax","slug":"series-order-must-be-a-python-integer","errorCode":null,"errorMessage":"series_order must be a Python integer.","messagePattern":"series_order must be a Python integer\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"jax/_src/scipy/special.py","lineNumber":1666,"sourceCode":"  `double-factorial\n  <https://en.wikipedia.org/wiki/Double_factorial>`_ operator.\n\n\n  Args:\n    x: an array of type `float32`, `float64`.\n    series_order: Positive Python integer. Maximum depth to\n      evaluate the asymptotic expansion. This is the `N` above.\n\n  Returns:\n    an array with `dtype=x.dtype`.\n\n  Raises:\n    TypeError: if `x.dtype` is not handled.\n    TypeError: if `series_order` is a not Python `integer.`\n    ValueError:  if `series_order` is not in `[0, 30]`.\n  \"\"\"\n  if not isinstance(series_order, int):\n    raise TypeError(\"series_order must be a Python integer.\")\n  if series_order < 0:\n    raise ValueError(\"series_order must be non-negative.\")\n  if series_order > 30:\n    raise ValueError(\"series_order must be <= 30.\")\n\n  x_arr = jnp.asarray(x)\n  dtype = lax.dtype(x_arr)\n\n  if dtype == np.float64:\n    lower_segment: np.ndarray = _LOGNDTR_FLOAT64_LOWER\n    upper_segment: np.ndarray = _LOGNDTR_FLOAT64_UPPER\n  elif dtype == np.float32:\n    lower_segment = _LOGNDTR_FLOAT32_LOWER\n    upper_segment = _LOGNDTR_FLOAT32_UPPER\n  else:\n    raise TypeError(f\"x.dtype={np.dtype(dtype)} is not supported.\")\n\n  # The basic idea here was ported from:","sourceCodeStart":1648,"sourceCodeEnd":1684,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/scipy/special.py#L1648-L1684","documentation":"jax.scipy.special.log_ndtr(x, series_order=3) requires series_order to be a plain Python int because it selects precomputed segment constants and controls unrolled series logic. Passing a float, np.float32, jax array, or other type raises TypeError.","triggerScenarios":"Calling log_ndtr(x, 5.0), log_ndtr(x, np.int64(5)) on some versions, or passing a traced/computed value as series_order (e.g. from a config dict or hyperparameter sweep).","commonSituations":"Hyperparameter sweeps where order comes from argparse floats or JSON configs; passing a JAX scalar in place of a Python int; wrapping log_ndtr in vmap/pmap with order accidentally treated as an array.","solutions":["Coerce: log_ndtr(x, int(series_order))","Keep series_order as a static Python int; if using jit, mark it nondiff_argnums/static or bake it via functools.partial","Validate type early: assert isinstance(series_order, int)"],"exampleFix":"// before\njax.scipy.special.log_ndtr(x, order)  # order = 5.0 from config\n// after\njax.scipy.special.log_ndtr(x, int(order))","handlingStrategy":"type-guard","validationCode":"series_order = int(series_order)\nassert isinstance(series_order, int)","typeGuard":"def py_int(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool)","tryCatchPattern":null,"preventionTips":["Coerce hyperparameters with int() at config load","Treat series_order as static in jit (partial or static_argnames)"],"tags":["jax","scipy-special","log-ndtr","type-validation"],"backgroundTag":"python-int-required","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}