open-mmlab/mmdetection · error · ValueError

tpfp_fn has to be a function or None, but got {tpfp_fn}

Error message

tpfp_fn has to be a function or None, but got {tpfp_fn}

What it means

eval_map accepts a custom tp/fp scoring function via tpfp_fn; after default selection logic (tpfp_default / tpfp_openimages), the value must be callable, otherwise ValueError.

Source

Thrown at mmdet/evaluation/functional/mean_ap.py:623

        nproc = min(nproc, num_imgs)
        pool = Pool(nproc)

    eval_results = []
    for i in range(num_classes):
        # get gt and det bboxes of this class
        cls_dets, cls_gts, cls_gts_ignore = get_cls_results(
            det_results, annotations, i)
        # choose proper function according to datasets to compute tp and fp
        if tpfp_fn is None:
            if dataset in ['det', 'vid']:
                tpfp_fn = tpfp_imagenet
            elif dataset in ['oid_challenge', 'oid_v6'] \
                    or use_group_of is True:
                tpfp_fn = tpfp_openimages
            else:
                tpfp_fn = tpfp_default
        if not callable(tpfp_fn):
            raise ValueError(
                f'tpfp_fn has to be a function or None, but got {tpfp_fn}')

        if num_imgs > 1:
            # compute tp and fp for each image with multiple processes
            args = []
            if use_group_of:
                # used in Open Images Dataset evaluation
                gt_group_ofs = get_cls_group_ofs(annotations, i)
                args.append(gt_group_ofs)
                args.append([use_group_of for _ in range(num_imgs)])
            if ioa_thr is not None:
                args.append([ioa_thr for _ in range(num_imgs)])

            tpfp = pool.starmap(
                tpfp_fn,
                zip(cls_dets, cls_gts, cls_gts_ignore,
                    [iou_thr for _ in range(num_imgs)],
                    [area_ranges for _ in range(num_imgs)],

View on GitHub (pinned to cfd5d3a985)

Solutions

  1. Pass the function object itself: tpfp_fn=tpfp_default or tpfp_fn=my_module.my_tpfp
  2. If loading from config, resolve the string to a callable (e.g. mmcv.utils.import_from_string / locate) before calling eval_map
  3. Omit tpfp_fn (pass None) to use the built-in default

Example fix

# before
from mmdet.evaluation.functional import tpfp_default
eval_map(..., tpfp_fn='tpfp_default')
# after
eval_map(..., tpfp_fn=tpfp_default)
Defensive patterns

Strategy: type-guard

Validate before calling

if tpfp_fn is not None:
    assert callable(tpfp_fn), 'tpfp_fn must be callable'

Type guard

def is_tpfp_fn(x) -> bool:
    return x is None or callable(x)

Prevention

When it happens

Trigger: Passing tpfp_fn as a string ('tpfp_default'), a module, or an uninitialized class instead of a function reference.

Common situations: Copying config snippets where tpfp_fn is serialized as a string; wrapping custom NMS scoring incorrectly.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of open-mmlab/mmdetection@cfd5d3a985 (2026-08-27). Data as JSON: /api/errors/a2a775bb8f7472c5. Report an issue: GitHub.