BoundaryML/baml · error
library handle is nil when looking up symbol '%s'
Error message
library handle is nil when looking up symbol '%s'
What it means
getSymbol guards against looking up a symbol (function) in a library whose dlopen handle is nil. This is an internal invariant check: it means loadLibrary failed but a nil handle was still passed to symbol lookup, or handle propagation lost the error.
Source
Thrown at engine/language_client_go/baml_go/lib_unix.go:50
dlopenErr = fmt.Errorf("%w (architecture mismatch)", dlopenErr)
} else if strings.Contains(dlErrStr, "cannot open shared object file") {
if strings.Contains(dlErrStr, "Permission denied") {
dlopenErr = fmt.Errorf("%w (permission denied)", dlopenErr)
} else {
dlopenErr = fmt.Errorf("%w (file not found or inaccessible)", dlopenErr)
}
} else if strings.Contains(dlErrStr, "image not found") || strings.Contains(dlErrStr, "no such file or directory") {
dlopenErr = fmt.Errorf("%w (library or dependency not found)", dlopenErr)
}
return nil, dlopenErr
}
return handle, nil
}
// getSymbol retrieves a symbol from the loaded library
func getSymbol(handle unsafe.Pointer, name string) (unsafe.Pointer, error) {
if handle == nil {
return nil, fmt.Errorf("library handle is nil when looking up symbol '%s'", name)
}
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
C.dlerror() // Clear any existing error
symbol := C.dlsym(handle, cName)
errStr := C.GoString(C.dlerror())
if symbol == nil {
errMsg := fmt.Sprintf("dlsym error for %s", name)
if errStr != "" {
errMsg += fmt.Sprintf(": %s", errStr)
} else {
errMsg += ": symbol not found"
}
return nil, fmt.Errorf("%s", errMsg)
}View on GitHub (pinned to bd85ce9dee)
Solutions
- Check and handle the error returned by loadLibrary before calling getSymbol
- Verify the library actually loaded (non-nil handle) before any symbol resolution
- Fix initialization flow so that a failed load short-circuits downstream symbol lookups
- Log the original dlopen error to identify why the handle was nil
Example fix
// before
handle, _ := loadLibrary(path)
sym, err := getSymbol(handle, "baml_init") // handle is nil
// after
handle, err := loadLibrary(path)
if err != nil {
return fmt.Errorf("library load failed: %w", err)
}
sym, err := getSymbol(handle, "baml_init") Defensive patterns
Strategy: type-guard
Validate before calling
handle, err := loadLibrary(path)
if err != nil || handle == nil {
return fmt.Errorf("library unavailable: %w", err)
} Type guard
func handleValid(h unsafe.Pointer) bool { return h != nil } Try / catch
sym, err := getSymbol(handle, name)
if err != nil && strings.Contains(err.Error(), "library handle is nil") {
// reload the library before retrying symbol lookup
handle, rerr := loadLibrary(path)
if rerr != nil { return rerr }
sym, err = getSymbol(handle, name)
} Prevention
- Never ignore the error return of loadLibrary
- Centralize library initialization and fail fast at startup
- Log the original dlopen failure whenever the handle is nil
When it happens
Trigger: Calling getSymbol(handle, name) when handle == nil — i.e., proceeding with symbol resolution after a failed dlopen or with an uninitialized handle.
Common situations: Caller code ignoring the loadLibrary error and continuing to resolve symbols; initialization ordering bugs where the library failed to load at startup but symbol lookups still run.
Related errors
- %s
- ErrLoadLibrary
- %w (library or dependency not found)
- invalid Go SDK import path `{import_path}`
- the Go generator requires `--sdk-import-path <MODULE>/baml_s
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/9b56ba2e23341edd.
Report an issue: GitHub.