mlflow/mlflow · error · MlflowException

Invalid lifecycle stage '{lifecycle_stage}'

Error message

Invalid lifecycle stage '{lifecycle_stage}'

What it means

LifecycleStage.matches_view_type(view_type, lifecycle_stage) first validates the lifecycle_stage string against the known stages (active/deleted). This MlflowException means an unrecognized lifecycle_stage string was passed. Callers such as _list_run_infos invoke it when filtering run listings by view type.

Source

Thrown at mlflow/entities/lifecycle_stage.py:26

    _VALID_STAGES = {ACTIVE, DELETED}

    @classmethod
    def view_type_to_stages(cls, view_type: int = ViewType.ALL) -> list[str]:
        stages = []
        if view_type in (ViewType.ACTIVE_ONLY, ViewType.ALL):
            stages.append(cls.ACTIVE)
        if view_type in (ViewType.DELETED_ONLY, ViewType.ALL):
            stages.append(cls.DELETED)
        return stages

    @classmethod
    def is_valid(cls, lifecycle_stage: str) -> bool:
        return lifecycle_stage in cls._VALID_STAGES

    @classmethod
    def matches_view_type(cls, view_type: int, lifecycle_stage: str) -> bool:
        if not cls.is_valid(lifecycle_stage):
            raise MlflowException(f"Invalid lifecycle stage '{lifecycle_stage}'")

        if view_type == ViewType.ALL:
            return True
        elif view_type == ViewType.ACTIVE_ONLY:
            return lifecycle_stage == LifecycleStage.ACTIVE
        elif view_type == ViewType.DELETED_ONLY:
            return lifecycle_stage == LifecycleStage.DELETED
        else:
            raise MlflowException(f"Invalid view type '{view_type}'")

View on GitHub (pinned to 6a27f2decc)

Solutions

  1. Use the LifecycleStage enum constants (LifecycleStage.ACTIVE / LifecycleStage.DELETED) instead of raw strings.
  2. Call LifecycleStage.is_valid(stage) before passing the value.
  3. Fix any corrupted lifecycle_stage values in the tracking store database (runs table).
  4. Lowercase/normalize user-supplied stage strings before use.

Example fix

// before
client.search_runs(experiment_ids, run_view_type=ViewType.ACTIVE_ONLY, filter_string="")  # stage read from DB as 'Active'
// after
from mlflow.entities import LifecycleStage
stage = (raw_stage or "").lower()
assert LifecycleStage.is_valid(stage), f"bad stage: {stage}"
Defensive patterns

Strategy: validation

Validate before calling

from mlflow.entities import LifecycleStage
if not LifecycleStage.is_valid(stage):
    raise ValueError(f"invalid lifecycle stage: {stage!r}")

Type guard

def is_valid_stage(s: object) -> bool:
    return isinstance(s, str) and LifecycleStage.is_valid(s)

Try / catch

try:
    runs = client.search_runs(exp_ids, run_view_type=vt)
except MlflowException as e:
    if "Invalid lifecycle stage" in str(e):
        fix_corrupted_run_records()
    raise

Prevention

When it happens

Trigger: Passing a lifecycle_stage string that is not exactly 'active' or 'deleted' (e.g. 'Active', 'live', '', 'archived') into search_runs with run_view_type filtering paths, or any code calling LifecycleStage.matches_view_type / _list_run_infos with a corrupt or custom stage value stored in run metadata.

Common situations: Case-sensitivity mistakes ('Active' vs 'active'); a corrupted run record in the tracking store with a bad stage value; third-party tooling writing custom lifecycle stage strings directly to the backend DB.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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