{"record":{"id":"80808db1ae00398d","repo":"google-research/timesfm","slug":"horizon-must-be-less-than-the-max-horizon-horizo","errorCode":null,"errorMessage":"Horizon must be less than the max horizon. {horizon} > {fc.max_horizon}.","messagePattern":"Horizon must be less than the max horizon\\. (.+?) > (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/timesfm/timesfm_2p5/timesfm_2p5_flax.py","lineNumber":559,"sourceCode":"      )\n\n    self.forecast_config = fc\n    self.model.compile(\n      context=self.forecast_config.max_context,\n      horizon=self.forecast_config.max_horizon,\n      per_core_batch_size=fc.per_core_batch_size,\n    )\n    self.per_core_batch_size = self.forecast_config.per_core_batch_size\n    self.num_devices = self.model.num_devices\n    self.global_batch_size = (\n      self.forecast_config.per_core_batch_size * self.model.num_devices\n    )\n\n    def compiled_decode_kernel(fc, horizon, inputs, masks):\n      inputs = jnp.array(inputs, dtype=jnp.float32)\n      masks = jnp.array(masks, dtype=jnp.bool)\n      if horizon > fc.max_horizon:\n        raise ValueError(\n          f\"Horizon must be less than the max horizon. {horizon} > {fc.max_horizon}.\"\n        )\n      to_trim = fc.max_horizon - horizon\n\n      inputs, masks, is_positive, mu, sigma = _before_model_decode(fc, inputs, masks)\n\n      pf_outputs, quantile_spreads, ar_outputs = self.model.compiled_decode(\n        fc.max_horizon, inputs, masks\n      )\n      if fc.force_flip_invariance:\n        flipped_pf_outputs, flipped_quantile_spreads, flipped_ar_outputs = (\n          self.model.compiled_decode(fc.max_horizon, -inputs, masks)\n        )\n      else:\n        flipped_pf_outputs, flipped_quantile_spreads, flipped_ar_outputs = (\n          None,\n          None,\n          None,","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/google-research/timesfm/blob/331c6d33cb1ac2611de3056d0ac7164aab6301eb/src/timesfm/timesfm_2p5/timesfm_2p5_flax.py#L541-L577","documentation":"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`).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call `model.compile()` with `max_horizon` >= the largest horizon you will ever request, then re-forecast","Clamp/validate each request's horizon to fc.max_horizon before calling forecast","Maintain a separate compiled model (or recompile) for long-horizon requests"],"exampleFix":"// before\nmodel.compile(forecast_config=ForecastConfig(max_context=512, max_horizon=96))\nmodel.forecast(horizon=200, inputs=inputs)\n// after\nmodel.compile(forecast_config=ForecastConfig(max_context=512, max_horizon=256))\nmodel.forecast(horizon=200, inputs=inputs)","handlingStrategy":"validation","validationCode":"max_horizon = model.forecast_config.max_horizon\nif horizon > max_horizon:\n    horizon = max_horizon  # or recompile with a larger max_horizon","typeGuard":"def request_fits(horizon: int, model) -> bool:\n    return horizon <= model.forecast_config.max_horizon","tryCatchPattern":"try:\n    point, quantiles = model.forecast(horizon, inputs)\nexcept ValueError as e:\n    if 'max horizon' in str(e):\n        model.compile(forecast_config=ForecastConfig(max_context=512, max_horizon=horizon))\n        point, quantiles = model.forecast(horizon, inputs)\n    else:\n        raise","preventionTips":["Compile with max_horizon >= the maximum horizon any request will use","Clamp incoming horizon values at the API boundary","Re-run compile() whenever the service's horizon requirement changes"],"tags":["python","validation","horizon-limit","compile"],"backgroundTag":"horizon-exceeds-limit","analyzedSha":"331c6d33cb1ac2611de3056d0ac7164aab6301eb","analyzedAt":"2026-08-29T01:04:23.138Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}