{"record":{"id":"d328e43ab46458e2","repo":"mudler/LocalAI","slug":"face-detect-dlopen-q-w","errorCode":null,"errorMessage":"face-detect: dlopen %q: %w","messagePattern":"face-detect: dlopen %q: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"backend/go/face-detect/main.go","lineNumber":36,"sourceCode":"\nvar (\n\taddr = flag.String(\"addr\", \"localhost:50051\", \"the address to connect to\")\n)\n\ntype LibFuncs struct {\n\tFuncPtr any\n\tName    string\n}\n\nfunc main() {\n\tlibName := os.Getenv(\"FACEDETECT_LIBRARY\")\n\tif libName == \"\" {\n\t\tlibName = \"libfacedetect.so\"\n\t}\n\n\tlib, err := purego.Dlopen(libName, purego.RTLD_NOW|purego.RTLD_GLOBAL)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"face-detect: dlopen %q: %w\", libName, err))\n\t}\n\n\t// Bound 1:1 to facedetect_capi.h. char*/float* returns are registered as\n\t// uintptr so the raw pointer can be freed via the matching capi free fn.\n\tlibFuncs := []LibFuncs{\n\t\t{&CppAbiVersion, \"facedetect_capi_abi_version\"},\n\t\t{&CppLoad, \"facedetect_capi_load\"},\n\t\t{&CppFree, \"facedetect_capi_free\"},\n\t\t{&CppLastError, \"facedetect_capi_last_error\"},\n\t\t{&CppFreeString, \"facedetect_capi_free_string\"},\n\t\t{&CppFreeVec, \"facedetect_capi_free_vec\"},\n\t\t{&CppEmbedPath, \"facedetect_capi_embed_path\"},\n\t\t{&CppEmbedRGB, \"facedetect_capi_embed_rgb\"},\n\t\t{&CppDetectJSON, \"facedetect_capi_detect_path_json\"},\n\t\t{&CppVerifyPaths, \"facedetect_capi_verify_paths\"},\n\t\t{&CppAnalyzeJSON, \"facedetect_capi_analyze_path_json\"},\n\t}\n\tfor _, lf := range libFuncs {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/backend/go/face-detect/main.go#L18-L54","documentation":"Startup panic of the Go face-detect backend when purego.Dlopen fails to load libfacedetect.so. The path comes from FACEDETECT_LIBRARY, defaulting to libfacedetect.so in the current search path. Because the backend binds every facedetect_capi_* symbol through purego, both load failure and later symbol resolution problems stem from the same .so.","triggerScenarios":"Launching the face-detect backend without the compiled libfacedetect.so on the loader path, with FACEDETECT_LIBRARY set to a nonexistent file, or with the .so present but built against unavailable shared dependencies.","commonSituations":"Missing build step for the C++ detector; deploying only the Go binary to a host without the native lib; FACEDETECT_LIBRARY stale after a reinstall moved the lib; CPU-only image lacking SIMD-capable build of the dependency.","solutions":["Check the file at $FACEDETECT_LIBRARY (or ./libfacedetect.so) exists and is readable","Build the native library per the backend's build instructions and place it beside the backend binary","Export FACEDETECT_LIBRARY=/absolute/path/to/libfacedetect.so","Run ldd on the .so and install any reported missing shared libraries"],"exampleFix":"# before\n./face-detect  # panic: face-detect: dlopen \"libfacedetect.so\": ...\n# after\nFACEDETECT_LIBRARY=/opt/localai/backends/libfacedetect.so ./face-detect","handlingStrategy":"validation","validationCode":"lib := os.Getenv(\"FACEDETECT_LIBRARY\"); if lib == \"\" { lib = \"libfacedetect.so\" }\nif _, err := os.Stat(lib); err != nil { log.Fatalf(\"face-detect: library %q missing: %v\", lib, err) }","typeGuard":"func libAvailable(path string) bool { _, err := os.Stat(path); return err == nil }","tryCatchPattern":null,"preventionTips":["Ship the .so with the backend binary in the same artifact","Verify FACEDETECT_LIBRARY in the environment of the service, not just your shell","Add a container healthcheck that stats the library before marking the backend ready"],"tags":["dlopen","native-library","go","backend","environment"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}