mudler/LocalAI · critical
ced: dlopen %q: %w
Error message
ced: dlopen %q: %w
What it means
Startup panic of the Go ced backend process when purego.Dlopen cannot load the C++ ced shared library. The library name comes from the CED_LIBRARY env var, defaulting to libced.dylib on macOS and libced.so elsewhere. RTLD_NOW|RTLD_GLOBAL means all symbols must resolve and the lib must be findable via the normal dynamic linker search path.
Source
Thrown at backend/go/ced/main.go:39
var addr = flag.String("addr", "localhost:50051", "the address to connect to")
type libFunc struct {
ptr any
name string
}
func main() {
libName := os.Getenv("CED_LIBRARY")
if libName == "" {
if runtime.GOOS == "darwin" {
libName = "libced.dylib"
} else {
libName = "libced.so"
}
}
lib, err := purego.Dlopen(libName, purego.RTLD_NOW|purego.RTLD_GLOBAL)
if err != nil {
panic(fmt.Errorf("ced: dlopen %q: %w", libName, err))
}
// Bound 1:1 to ced_capi.h. char*-returning functions are declared uintptr
// so we can free the same pointer with ced_capi_free_string after copying
// (purego's string return would copy and leak the original).
for _, lf := range []libFunc{
{&CppAbiVersion, "ced_capi_abi_version"},
{&CppLoad, "ced_capi_load"},
{&CppFree, "ced_capi_free"},
{&CppLastError, "ced_capi_last_error"},
{&CppNumClasses, "ced_capi_num_classes"},
{&CppSampleRate, "ced_capi_sample_rate"},
{&CppClassifyPathJSON, "ced_capi_classify_path_json"},
{&CppClassifyPcmJSON, "ced_capi_classify_pcm_json"},
{&CppFreeString, "ced_capi_free_string"},
} {
purego.RegisterLibFunc(lf.ptr, lib, lf.name)
}View on GitHub (pinned to 44413a9d06)
Solutions
- Verify the library exists: ls -l $CED_LIBRARY or ./libced.so in the backend working directory
- Rebuild the C++ side of the backend (see the ced backend's build script/Dockerfile) so the .so is produced next to the binary
- Set CED_LIBRARY to the absolute path of the library and re-run
- Diagnose missing transitive deps with ldd libced.so (Linux) or otool -L libced.dylib (macOS) and install them
- Confirm architecture match with file libced.so vs the Go binary
Example fix
# before ./ced # panic: ced: dlopen "libced.so": ... # after CED_LIBRARY=/opt/localai/lib/libced.so ./ced
Defensive patterns
Strategy: validation
Validate before calling
lib := os.Getenv("CED_LIBRARY"); if lib == "" { lib = "libced.so" }
if _, err := os.Stat(lib); errors.Is(err, fs.ErrNotExist) {
lib = resolveBuiltArtifact() // or fail fast with a clear message
} Type guard
func libAvailable(path string) bool { _, err := os.Stat(path); return err == nil } Try / catch
// panic in main cannot be caught; guard before Dlopen
if err := checkDeps(libName); err != nil { log.Fatalf("ced: preload check: %v", err) } Prevention
- Run ldd on the .so in the deploy image as a CI step
- Set CED_LIBRARY to an absolute path in service units
- Build the native lib and Go backend from the same commit
When it happens
Trigger: Starting the ced backend when libced.so was not built/installed, CED_LIBRARY points to a wrong path, the lib exists but a transitive dependency (OpenCV, ONNX Runtime, etc.) is missing, or an arm64/x86_64 architecture mismatch exists between the Go binary and the .so.
Common situations: Running a manually built core binary without running the backend's build step; container images missing runtime libs; copying a library built on another distro with a different glibc; forgetting to export CED_LIBRARY when the lib is in a nonstandard directory.
Related errors
- face-detect: dlopen %q: %w
- moss-transcribe-cpp: dlopen %q: %w
- parakeet-cpp: dlopen %q: %w
- voice-detect: dlopen %q: %w
- trellis2 ABI mismatch: library reports %d, backend built for
AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15).
Data as JSON: /api/errors/f42f41c4b63d0630.
Report an issue: GitHub.