mudler/LocalAI · error · ValueError

onnx_direct engine requires both detector_onnx and…

Error message

onnx_direct engine requires both detector_onnx and recognizer_onnx options

What it means

Raised by OnnxDirectEngine.prepare() when the insightface backend is loaded with engine 'onnx_direct' but the LoadModel options dict lacks 'detector_onnx' or 'recognizer_onnx' (or either is an empty string). The onnx_direct engine bypasses the insightface package and drives OpenCV YuNet + a recognition ONNX model directly, so it needs explicit paths to both ONNX files. Without them it cannot construct cv2.FaceDetectorYN or the recognizer.

Solutions

  1. Add both options to the model config: detector_onnx: /path/to/yunet.onnx and recognizer_onnx: /path/to/recognizer.onnx (e.g. from the insightface buffalo_l model: det_10g.onnx and w600k_r50.onnx)
  2. Verify the option keys are spelled exactly 'detector_onnx' and 'recognizer_onnx' and their values are non-empty strings
  3. Paths are resolved via _resolve_model_path with the model's _model_dir, so relative names work if the files sit next to the model config; otherwise use absolute paths
  4. If you do not have separate ONNX files, drop the engine option and use the default insightface engine instead

Example fix

# before
options:
  engine: onnx_direct

# after
options:
  engine: onnx_direct
  detector_onnx: /models/buffalo_l/det_10g.onnx
  recognizer_onnx: /models/buffalo_l/w600k_r50.onnx
Defensive patterns

Strategy: validation

Validate before calling

def validate_onnx_direct_options(options: dict) -> None:
    if str(options.get("engine", "insightface")).strip().lower() not in {"onnx_direct", "onnx-direct", "opencv"}:
        return
    import os
    for key in ("detector_onnx", "recognizer_onnx"):
        val = options.get(key, "")
        if not val or not isinstance(val, str):
            raise ValueError(f"engine onnx_direct requires a non-empty {key} option")
        if not os.path.isfile(val) and not os.path.isfile(os.path.join(str(options.get("_model_dir", ".")), val)):
            raise FileNotFoundError(f"{key}={val!r} not found")

Try / catch

try:
    engine.prepare(options)
except ValueError as e:
    if "detector_onnx" in str(e):
        # config error: report which keys are missing and abort load
        raise ConfigError(str(e)) from e
    raise

Prevention

When it happens

Trigger: Loading the insightface backend with options {"engine": "onnx_direct"} but omitting detector_onnx/recognizer_onnx; passing an empty string for either key; misspelling the option keys (e.g. detector_path instead of detector_onnx).

Common situations: Switching from the default insightface engine to onnx_direct to avoid the heavy insightface Python dependency but keeping the old minimal options; configuring via YAML model config where the options block was copy-pasted from a non-onnx_direct model.

Related errors


AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15). Data as JSON: /api/errors/8440d0fdcb57c25e. Report an issue: GitHub.

Appendix: source

Thrown at backend/python/insightface/engines.py:399

    exposes a C++-level API via cv2.FaceDetectorYN which accepts the
    ONNX file directly; SFace is driven through cv2.FaceRecognizerSF.
    Both are Apache 2.0 licensed.
    """

    def __init__(self) -> None:
        self.detector_path: str = ""
        self.recognizer_path: str = ""
        self.input_size: tuple[int, int] = (320, 320)
        self.det_thresh: float = 0.5
        self._detector: Any = None
        self._recognizer: Any = None
        self._antispoofer: Antispoofer | None = None

    def prepare(self, options: dict[str, str]) -> None:
        raw_det = options.get("detector_onnx", "")
        raw_rec = options.get("recognizer_onnx", "")
        if not raw_det or not raw_rec:
            raise ValueError(
                "onnx_direct engine requires both detector_onnx and recognizer_onnx options"
            )
        model_dir = options.get("_model_dir")
        self.detector_path = _resolve_model_path(raw_det, model_dir=model_dir)
        self.recognizer_path = _resolve_model_path(raw_rec, model_dir=model_dir)
        self.input_size = _parse_det_size(options.get("det_size", "320x320"))
        self.det_thresh = float(options.get("det_thresh", "0.5"))
        self._antispoofer = _build_antispoofer(options, model_dir)

        # YuNet is a fixed-size detector; size is reset per detect() call to
        # match the input frame.
        self._detector = cv2.FaceDetectorYN.create(
            self.detector_path,
            "",
            self.input_size,
            score_threshold=self.det_thresh,
            nms_threshold=0.3,
            top_k=5000,

View on GitHub (pinned to 44413a9d06)