666ghj/MiroFish · error · StarHistoryError

chart coordinates must be finite

Error message

chart coordinates must be finite

What it means

Raised in `_monotone_x_path` (scripts/star_history.py:786), the D3-curveMonotoneX-equivalent SVG path builder used by `render_svg`. Every (x, y) chart point must be a finite float; NaN or ±infinity cannot be serialized into valid SVG path coordinates and would poison the Steffen monotonic interpolation.

Source

Thrown at scripts/star_history.py:786

    if value < 0:
        return -1
    if value > 0:
        return 1
    return 0


def _monotone_x_path(points: Sequence[tuple[float, float]]) -> str:
    """Return a D3 curveMonotoneX-equivalent SVG path.

    D3 uses Steffen monotonic interpolation: interior tangents are limited so a
    smooth cubic cannot overshoot a monotonic run. This small implementation
    keeps the Star History curve shape without adding a JavaScript dependency.
    """

    normalized: list[tuple[float, float]] = []
    for x, y in points:
        if not math.isfinite(x) or not math.isfinite(y):
            raise StarHistoryError("chart coordinates must be finite")
        if normalized and x < normalized[-1][0]:
            raise StarHistoryError("chart coordinates must be ordered")
        if normalized and x == normalized[-1][0]:
            normalized[-1] = (x, y)
        else:
            normalized.append((x, y))

    if not normalized:
        return ""

    start_x, start_y = normalized[0]
    commands = [f"M{_format_float(start_x)},{_format_float(start_y)}"]
    if len(normalized) == 1:
        return "".join(commands)
    if len(normalized) == 2:
        end_x, end_y = normalized[1]
        commands.append(f"L{_format_float(end_x)},{_format_float(end_y)}")
        return "".join(commands)

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Run `validate_state(state)` on the exact state object before `render_svg` — the public renderer does this too, so a hit means the bad value appears only after scaling; check the state file for odd dates or star counts.
  2. If you call `_monotone_x_path` directly, filter/replace non-finite points first: `pts = [(x, y) for x, y in pts if math.isfinite(x) and math.isfinite(y)]`.
  3. In forked scaling code, guard degenerate ranges (`if x_max == x_min: x_max = x_min + 1`) so no inf emerges from division.
  4. Rebuild the state from a fresh backfill/snapshot if the file was hand-edited.

Example fix

# before: passing raw computed points
path = _monotone_x_path(scaled_points)  # may contain nan/inf -> raises

# after: sanitize before calling
scaled_points = [(x, y) for x, y in scaled_points if math.isfinite(x) and math.isfinite(y)]
path = _monotone_x_path(scaled_points)
Defensive patterns

Strategy: validation

Validate before calling

import math

def finite_points(points):
    return all(math.isfinite(x) and math.isfinite(y) for x, y in points)

assert finite_points(scaled_points), "chart math produced non-finite coordinates"
path = _monotone_x_path(scaled_points)

Try / catch

try:
    svg = render_svg(state, theme)
except StarHistoryError as exc:
    if "must be finite" in str(exc):
        raise ValueError("state produced non-finite chart coordinates; regenerate state") from exc
    raise

Prevention

When it happens

Trigger: `render_svg(state, theme)` reaching the path builder with a point whose x or y is NaN/inf. Points derive from `_chart_points(state)` (dates as x via matplotlib-style date numbers, stars as y) followed by axis scaling — non-finite values appear when state contains corrupt dates/stars that slipped past `validate_state`, or when custom code calls `_monotone_x_path` directly with computed coordinates that divide by zero (e.g. scale = 1/(max-min) with max==min).

Common situations: Hand-edited state JSON with nulls coerced to NaN upstream; a fork that changes chart scaling and introduces a zero-denominator; direct use of the private path helper in other tooling with unfiltered data.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/4700432138fb7287. Report an issue: GitHub.