google-research/timesfm · error · ValueError

train_dynamic_categorical_covariates and test_dynamic_catego

Error message

train_dynamic_categorical_covariates and test_dynamic_categorical_covariates must be both present or both absent.

What it means

Identical symmetry check as error 35 but for dynamic categorical covariates: train_dynamic_categorical_covariates and test_dynamic_categorical_covariates must both be present or both absent, otherwise _assert_covariates raises this ValueError.

Source

Thrown at src/timesfm/utils/xreg_lib.py:234

      and not self.test_dynamic_numerical_covariates
    ) or (
      not self.train_dynamic_numerical_covariates
      and self.test_dynamic_numerical_covariates
    ):
      raise ValueError(
        "train_dynamic_numerical_covariates and"
        " test_dynamic_numerical_covariates must be both present or both"
        " absent."
      )

    if (
      self.train_dynamic_categorical_covariates
      and not self.test_dynamic_categorical_covariates
    ) or (
      not self.train_dynamic_categorical_covariates
      and self.test_dynamic_categorical_covariates
    ):
      raise ValueError(
        "train_dynamic_categorical_covariates and"
        " test_dynamic_categorical_covariates must be both present or both"
        " absent."
      )

    # Check keys.
    for dict_a, dict_b, dict_a_name, dict_b_name in (
      (
        self.train_dynamic_numerical_covariates,
        self.test_dynamic_numerical_covariates,
        "train_dynamic_numerical_covariates",
        "test_dynamic_numerical_covariates",
      ),
      (
        self.train_dynamic_categorical_covariates,
        self.test_dynamic_categorical_covariates,
        "train_dynamic_categorical_covariates",
        "test_dynamic_categorical_covariates",

View on GitHub (pinned to 331c6d33cb)

Solutions

  1. Supply both train and test dynamic categorical covariate dicts with the same keys.
  2. Pass None for both if categorical covariates are not used.
  3. Fill test-side values with known future values (e.g. planned promotions, calendar categories).

Example fix

// before
XregCovariates(train_dynamic_categorical_covariates={"promo": train_promo}, test_dynamic_categorical_covariates=None)
// after
XregCovariates(train_dynamic_categorical_covariates={"promo": train_promo}, test_dynamic_categorical_covariates={"promo": test_promo})
Defensive patterns

Strategy: validation

Validate before calling

assert (train_cat is None) == (test_cat is None), \
    "train and test dynamic categorical covariates must be both present or both absent"

Type guard

def categoricals_symmetric(train_cat, test_cat) -> bool:
    return (train_cat is None) == (test_cat is None)

Try / catch

try:
    forecaster.forecast_with_covariates(...)
except ValueError as e:
    if "dynamic_categorical_covariates must be both present" in str(e):
        test_cat = {k: planned_values[k] for k in train_cat}
        forecaster.forecast_with_covariates(...)
    else:
        raise

Prevention

When it happens

Trigger: Calling create_covariate_matrix (via forecast_with_covariates) with train_dynamic_categorical_covariates set and test_dynamic_categorical_covariates None, or the reverse.

Common situations: Adding categorical regressors (e.g. promotion flags) for training only; forgetting that future category values must also be supplied; partial refactoring of covariate code.

Related errors


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