mlflow/mlflow · error · MlflowException

When updating a scorer, provided sample rate must be a numbe

Error message

When updating a scorer, provided sample rate must be a number

What it means

Scorer.update() validates sampling_config.sample_rate: unlike start, None is allowed (meaning 'unchanged'), but any other non-numeric value raises MlflowException.invalid_parameter_value. This protects the backend from storing a malformed sampling rate during a partial update.

Source

Thrown at mlflow/genai/scorers/base.py:1090

                )
                print(f"Updated sample rate: {updated_scorer.sample_rate}")

                # Update to add filtering criteria
                filtered_scorer = updated_scorer.update(
                    sampling_config=ScorerSamplingConfig(filter_string="YOUR_FILTER_STRING")
                )
                print(f"Added filter: {filtered_scorer.filter_string}")
        """
        from mlflow.genai.scorers.registry import (
            DatabricksStore,
            _get_scorer_store,
        )

        self._check_can_be_registered()

        sample_rate = sampling_config.sample_rate
        if sample_rate is not None and not isinstance(sample_rate, (int, float)):
            raise MlflowException.invalid_parameter_value(
                "When updating a scorer, provided sample rate must be a number"
            )

        scorer_name = name or self.name
        store = _get_scorer_store()

        if isinstance(store, DatabricksStore):
            return store.update_registered_scorer(
                name=scorer_name,
                scorer=self,
                sample_rate=sample_rate,
                filter_string=sampling_config.filter_string,
                experiment_id=experiment_id,
            )

        # For MLflow backend, use provided experiment_id or fall back to scorer's experiment_id
        exp_id = experiment_id or self._experiment_id
        if exp_id is None:

View on GitHub (pinned to 6a27f2decc)

Solutions

  1. Pass either None (leave unchanged) or a numeric int/float value.
  2. Coerce: rate = None if raw is None else float(raw).
  3. Normalize config ingestion (cast at load time) so update() never sees strings.

Example fix

// before
scorer.update(sampling_config=ScorerSamplingConfig(sample_rate="0.25"))
// after
raw = "0.25"
scorer.update(sampling_config=ScorerSamplingConfig(sample_rate=None if raw is None else float(raw)))
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_rate(raw):
    if raw is None:
        return None
    if isinstance(raw, str):
        return float(raw)
    return raw

scorer.update(sampling_config=ScorerSamplingConfig(sample_rate=normalize_rate(raw)))

Type guard

def is_rate_or_none(v) -> bool:
    return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool))

Try / catch

try:
    scorer.update(sampling_config=cfg)
except MlflowException as e:
    if "must be a number" in str(e):
        scorer.update(sampling_config=ScorerSamplingConfig(sample_rate=float(cfg.sample_rate)))
    else:
        raise

Prevention

When it happens

Trigger: scorer.update(...) with a ScorerSamplingConfig whose sample_rate is a string ("0.5"), bool, Decimal, or other non-int/float while not being None.

Common situations: Partial-update code paths forwarding raw form/config values; YAML/env-loaded settings arriving as strings; frameworks passing sentinel objects instead of None.

Related errors


AI-assisted analysis of mlflow/mlflow@6a27f2decc (2026-08-29). Data as JSON: /api/errors/f5757bbc4b347050. Report an issue: GitHub.