ultralytics/ultralytics · error · ValueError

❌ Task '{task}' doesn't support 'mode=track', valid tasks ar

Error message

❌ Task '{task}' doesn't support 'mode=track', valid tasks are {', '.join(trackable)}

What it means

on_predict_start (wired into mode=track) accepts tracking only for tasks whose Results carry boxes: detect, segment, pose, obb. If predictor.args.task is a known TASKS entry but not one of those — classify, semantic, depth — trackers cannot be attached because there are no boxes to associate across frames, so ValueError is raised listing the valid tasks. Unknown third-party task names are deliberately left alone.

Source

Thrown at ultralytics/trackers/track.py:44

    "deepocsort": DeepOCSORT,
}


def on_predict_start(predictor: object, persist: bool = False) -> None:
    """Initialize trackers for object tracking during prediction.

    Args:
        predictor (ultralytics.engine.predictor.BasePredictor): The predictor object to initialize trackers for.
        persist (bool, optional): Whether to reuse existing trackers if they are already attached.

    Examples:
        Initialize trackers for a predictor object
        >>> predictor = SomePredictorClass()
        >>> on_predict_start(predictor, persist=True)
    """
    trackable = ("detect", "segment", "pose", "obb")  # tasks whose results carry boxes, in canonical order
    if (task := predictor.args.task) in TASKS and task not in trackable:  # unknown third-party tasks are left alone
        raise ValueError(f"❌ Task '{task}' doesn't support 'mode=track', valid tasks are {', '.join(trackable)}")

    if hasattr(predictor, "trackers") and persist:
        return

    tracker = check_yaml(predictor.args.tracker)
    cfg = IterableSimpleNamespace(**YAML.load(tracker))
    cfg.device = predictor.device  # run any ReID encoder on the predictor's device

    if cfg.tracker_type not in TRACKER_MAP:
        raise AssertionError(f"Only {sorted(TRACKER_MAP)} are supported for now, but got '{cfg.tracker_type}'")

    predictor._feats = None  # reset ReID pre-hook state
    if hasattr(predictor, "_hook"):
        predictor._hook.remove()
    if hasattr(predictor, "_orig_postprocess"):  # restore any raw-preds wrapper left by a prior TRACKTRACK run
        predictor.postprocess = predictor._orig_postprocess
        del predictor._orig_postprocess
    if cfg.tracker_type in {"botsort", "tracktrack", "deepocsort"} and cfg.with_reid and cfg.model == "auto":

View on GitHub (pinned to 0449ea011c)

Solutions

  1. Use a detect, segment, pose, or obb model for tracking, e.g. YOLO('yolo11n.pt').track(source='video.mp4')
  2. If you need per-frame classification over video, use model.predict(...) in a loop instead of track
  3. Verify the checkpoint's task before calling track (model.task)

Example fix

# before
model = YOLO('yolo11n-cls.pt')
results = model.track(source='video.mp4')  # ValueError

# after
model = YOLO('yolo11n.pt')  # detect model
results = model.track(source='video.mp4')
Defensive patterns

Strategy: type-guard

Validate before calling

TRACKABLE = ('detect', 'segment', 'pose', 'obb')
assert model.task in TRACKABLE, f"track() needs one of {TRACKABLE}, got {model.task}"

Type guard

def is_trackable(model) -> bool:
    return model.task in {'detect', 'segment', 'pose', 'obb'}

Try / catch

try:
    results = model.track(source=src)
except ValueError as e:
    if "doesn't support 'mode=track'" in str(e):
        results = [r for r in model.predict(source=src, stream=True)]  # frames without IDs

Prevention

When it happens

Trigger: Calling model.track(...) on a classification/semantic/depth model: YOLO('yolo11n-cls.pt').track(source=...), or a semantic/depth checkpoint with mode=track in the CLI.

Common situations: Reusing a tracking script template with a classification model; selecting the wrong checkpoint in a config; assuming track() is a generic video mode for all tasks.

Related errors


AI-assisted analysis of ultralytics/ultralytics@0449ea011c (2026-08-15). Data as JSON: /api/errors/5066f05be0cf2bd7. Report an issue: GitHub.