{"record":{"id":"8440d0fdcb57c25e","repo":"mudler/LocalAI","slug":"onnx-direct-engine-requires-both-detector-onnx-and","errorCode":null,"errorMessage":"onnx_direct engine requires both detector_onnx and recognizer_onnx options","messagePattern":"onnx_direct engine requires both detector_onnx and recognizer_onnx options","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/python/insightface/engines.py","lineNumber":399,"sourceCode":"    exposes a C++-level API via cv2.FaceDetectorYN which accepts the\n    ONNX file directly; SFace is driven through cv2.FaceRecognizerSF.\n    Both are Apache 2.0 licensed.\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.detector_path: str = \"\"\n        self.recognizer_path: str = \"\"\n        self.input_size: tuple[int, int] = (320, 320)\n        self.det_thresh: float = 0.5\n        self._detector: Any = None\n        self._recognizer: Any = None\n        self._antispoofer: Antispoofer | None = None\n\n    def prepare(self, options: dict[str, str]) -> None:\n        raw_det = options.get(\"detector_onnx\", \"\")\n        raw_rec = options.get(\"recognizer_onnx\", \"\")\n        if not raw_det or not raw_rec:\n            raise ValueError(\n                \"onnx_direct engine requires both detector_onnx and recognizer_onnx options\"\n            )\n        model_dir = options.get(\"_model_dir\")\n        self.detector_path = _resolve_model_path(raw_det, model_dir=model_dir)\n        self.recognizer_path = _resolve_model_path(raw_rec, model_dir=model_dir)\n        self.input_size = _parse_det_size(options.get(\"det_size\", \"320x320\"))\n        self.det_thresh = float(options.get(\"det_thresh\", \"0.5\"))\n        self._antispoofer = _build_antispoofer(options, model_dir)\n\n        # YuNet is a fixed-size detector; size is reset per detect() call to\n        # match the input frame.\n        self._detector = cv2.FaceDetectorYN.create(\n            self.detector_path,\n            \"\",\n            self.input_size,\n            score_threshold=self.det_thresh,\n            nms_threshold=0.3,\n            top_k=5000,","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/backend/python/insightface/engines.py#L381-L417","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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)","Verify the option keys are spelled exactly 'detector_onnx' and 'recognizer_onnx' and their values are non-empty strings","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","If you do not have separate ONNX files, drop the engine option and use the default insightface engine instead"],"exampleFix":"# before\noptions:\n  engine: onnx_direct\n\n# after\noptions:\n  engine: onnx_direct\n  detector_onnx: /models/buffalo_l/det_10g.onnx\n  recognizer_onnx: /models/buffalo_l/w600k_r50.onnx","handlingStrategy":"validation","validationCode":"def validate_onnx_direct_options(options: dict) -> None:\n    if str(options.get(\"engine\", \"insightface\")).strip().lower() not in {\"onnx_direct\", \"onnx-direct\", \"opencv\"}:\n        return\n    import os\n    for key in (\"detector_onnx\", \"recognizer_onnx\"):\n        val = options.get(key, \"\")\n        if not val or not isinstance(val, str):\n            raise ValueError(f\"engine onnx_direct requires a non-empty {key} option\")\n        if not os.path.isfile(val) and not os.path.isfile(os.path.join(str(options.get(\"_model_dir\", \".\")), val)):\n            raise FileNotFoundError(f\"{key}={val!r} not found\")","typeGuard":null,"tryCatchPattern":"try:\n    engine.prepare(options)\nexcept ValueError as e:\n    if \"detector_onnx\" in str(e):\n        # config error: report which keys are missing and abort load\n        raise ConfigError(str(e)) from e\n    raise","preventionTips":["Keep a schema/checklist for each engine's required options and validate before LoadModel","Smoke-test ONNX paths during deployment, not at first inference"],"tags":["python","insightface","onnx","configuration","model-loading"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}