google-research/timesfm · error · ValueError

Horizon must be less than the max horizon. {horizon} > {fc.m

Error message

Horizon must be less than the max horizon. {horizon} > {fc.max_horizon}.

What it means

The compiled decode kernel was specialized at compile time for `fc.max_horizon` output steps. When invoked, each request's `horizon` must be <= max_horizon; larger requests cannot be served by the compiled computation, so the kernel raises ValueError with the requested vs allowed horizon. Requests smaller than max_horizon are fine (output is trimmed by `max_horizon - horizon`).

Source

Thrown at src/timesfm/timesfm_2p5/timesfm_2p5_flax.py:559

      )

    self.forecast_config = fc
    self.model.compile(
      context=self.forecast_config.max_context,
      horizon=self.forecast_config.max_horizon,
      per_core_batch_size=fc.per_core_batch_size,
    )
    self.per_core_batch_size = self.forecast_config.per_core_batch_size
    self.num_devices = self.model.num_devices
    self.global_batch_size = (
      self.forecast_config.per_core_batch_size * self.model.num_devices
    )

    def compiled_decode_kernel(fc, horizon, inputs, masks):
      inputs = jnp.array(inputs, dtype=jnp.float32)
      masks = jnp.array(masks, dtype=jnp.bool)
      if horizon > fc.max_horizon:
        raise ValueError(
          f"Horizon must be less than the max horizon. {horizon} > {fc.max_horizon}."
        )
      to_trim = fc.max_horizon - horizon

      inputs, masks, is_positive, mu, sigma = _before_model_decode(fc, inputs, masks)

      pf_outputs, quantile_spreads, ar_outputs = self.model.compiled_decode(
        fc.max_horizon, inputs, masks
      )
      if fc.force_flip_invariance:
        flipped_pf_outputs, flipped_quantile_spreads, flipped_ar_outputs = (
          self.model.compiled_decode(fc.max_horizon, -inputs, masks)
        )
      else:
        flipped_pf_outputs, flipped_quantile_spreads, flipped_ar_outputs = (
          None,
          None,
          None,

View on GitHub (pinned to 331c6d33cb)

Solutions

  1. Call `model.compile()` with `max_horizon` >= the largest horizon you will ever request, then re-forecast
  2. Clamp/validate each request's horizon to fc.max_horizon before calling forecast
  3. Maintain a separate compiled model (or recompile) for long-horizon requests

Example fix

// before
model.compile(forecast_config=ForecastConfig(max_context=512, max_horizon=96))
model.forecast(horizon=200, inputs=inputs)
// after
model.compile(forecast_config=ForecastConfig(max_context=512, max_horizon=256))
model.forecast(horizon=200, inputs=inputs)
Defensive patterns

Strategy: validation

Validate before calling

max_horizon = model.forecast_config.max_horizon
if horizon > max_horizon:
    horizon = max_horizon  # or recompile with a larger max_horizon

Type guard

def request_fits(horizon: int, model) -> bool:
    return horizon <= model.forecast_config.max_horizon

Try / catch

try:
    point, quantiles = model.forecast(horizon, inputs)
except ValueError as e:
    if 'max horizon' in str(e):
        model.compile(forecast_config=ForecastConfig(max_context=512, max_horizon=horizon))
        point, quantiles = model.forecast(horizon, inputs)
    else:
        raise

Prevention

When it happens

Trigger: Calling `model.forecast(horizon=H, ...)` with H > the max_horizon used at compile(); per-request horizons that vary and sometimes exceed the compiled maximum; compiling with a small max_horizon for speed then asking for a longer forecast.

Common situations: Interactive forecasts where users pick arbitrary horizons; a batch job whose horizon grew after the model was compiled at service startup; forgetting that compile-time max_horizon caps all later forecast calls.

Related errors


AI-assisted analysis of google-research/timesfm@331c6d33cb (2026-08-29). Data as JSON: /api/errors/80808db1ae00398d. Report an issue: GitHub.