{"record":{"id":"9b56ba2e23341edd","repo":"BoundaryML/baml","slug":"library-handle-is-nil-when-looking-up-symbol-s","errorCode":null,"errorMessage":"library handle is nil when looking up symbol '%s'","messagePattern":"library handle is nil when looking up symbol '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/language_client_go/baml_go/lib_unix.go","lineNumber":50,"sourceCode":"\t\t\tdlopenErr = fmt.Errorf(\"%w (architecture mismatch)\", dlopenErr)\n\t\t} else if strings.Contains(dlErrStr, \"cannot open shared object file\") {\n\t\t\tif strings.Contains(dlErrStr, \"Permission denied\") {\n\t\t\t\tdlopenErr = fmt.Errorf(\"%w (permission denied)\", dlopenErr)\n\t\t\t} else {\n\t\t\t\tdlopenErr = fmt.Errorf(\"%w (file not found or inaccessible)\", dlopenErr)\n\t\t\t}\n\t\t} else if strings.Contains(dlErrStr, \"image not found\") || strings.Contains(dlErrStr, \"no such file or directory\") {\n\t\t\tdlopenErr = fmt.Errorf(\"%w (library or dependency not found)\", dlopenErr)\n\t\t}\n\t\treturn nil, dlopenErr\n\t}\n\treturn handle, nil\n}\n\n// getSymbol retrieves a symbol from the loaded library\nfunc getSymbol(handle unsafe.Pointer, name string) (unsafe.Pointer, error) {\n\tif handle == nil {\n\t\treturn nil, fmt.Errorf(\"library handle is nil when looking up symbol '%s'\", name)\n\t}\n\n\tcName := C.CString(name)\n\tdefer C.free(unsafe.Pointer(cName))\n\n\tC.dlerror() // Clear any existing error\n\tsymbol := C.dlsym(handle, cName)\n\terrStr := C.GoString(C.dlerror())\n\n\tif symbol == nil {\n\t\terrMsg := fmt.Sprintf(\"dlsym error for %s\", name)\n\t\tif errStr != \"\" {\n\t\t\terrMsg += fmt.Sprintf(\": %s\", errStr)\n\t\t} else {\n\t\t\terrMsg += \": symbol not found\"\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s\", errMsg)\n\t}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_go/baml_go/lib_unix.go#L32-L68","documentation":"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.","triggerScenarios":"Calling getSymbol(handle, name) when handle == nil — i.e., proceeding with symbol resolution after a failed dlopen or with an uninitialized handle.","commonSituations":"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.","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"],"exampleFix":"// before\nhandle, _ := loadLibrary(path)\nsym, err := getSymbol(handle, \"baml_init\") // handle is nil\n// after\nhandle, err := loadLibrary(path)\nif err != nil {\n    return fmt.Errorf(\"library load failed: %w\", err)\n}\nsym, err := getSymbol(handle, \"baml_init\")","handlingStrategy":"type-guard","validationCode":"handle, err := loadLibrary(path)\nif err != nil || handle == nil {\n    return fmt.Errorf(\"library unavailable: %w\", err)\n}","typeGuard":"func handleValid(h unsafe.Pointer) bool { return h != nil }","tryCatchPattern":"sym, err := getSymbol(handle, name)\nif err != nil && strings.Contains(err.Error(), \"library handle is nil\") {\n    // reload the library before retrying symbol lookup\n    handle, rerr := loadLibrary(path)\n    if rerr != nil { return rerr }\n    sym, err = getSymbol(handle, name)\n}","preventionTips":["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"],"tags":["go","dlsym","native-library","invariant"],"backgroundTag":"null-argument","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}