{"record":{"id":"8bd9ebf4de0c780f","repo":"BoundaryML/baml","slug":"dlclose-failed","errorCode":null,"errorMessage":"dlclose failed","messagePattern":"dlclose failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/language_client_go/baml_go/lib_unix.go","lineNumber":82,"sourceCode":"\t\t} else {\n\t\t\terrMsg += \": symbol not found\"\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s\", errMsg)\n\t}\n\treturn symbol, nil\n}\n\n// closeLibrary closes the loaded library\nfunc closeLibrary(handle unsafe.Pointer) error {\n\tif handle == nil {\n\t\treturn nil\n\t}\n\tif C.dlclose(handle) != 0 {\n\t\terrStr := C.GoString(C.dlerror())\n\t\tif errStr != \"\" {\n\t\t\treturn fmt.Errorf(\"dlclose failed: %s\", errStr)\n\t\t}\n\t\treturn fmt.Errorf(\"dlclose failed\")\n\t}\n\treturn nil\n}\n\n// platformInit performs any platform-specific initialization\nfunc platformInit() error {\n\t// Unix doesn't need special initialization\n\treturn nil\n}","sourceCodeStart":64,"sourceCodeEnd":91,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_go/baml_go/lib_unix.go#L64-L91","documentation":"This is the fallback message returned by closeLibrary when dlclose() fails but dlerror() returns an empty string, so no OS detail is available. Like the detailed variant, it means the BAML native shared library handle could not be unloaded on Unix. The absence of a detail string makes a stale/invalid handle the most likely cause.","triggerScenarios":"closeLibrary invoked with a handle for which C.dlclose returns nonzero and C.dlerror() yields no message — typically a handle that was already closed or was never validly produced by dlopen.","commonSituations":"Teardown code that runs twice (e.g. via defer plus explicit close); process shutdown hooks racing with each other; embedded environments where dlclose cannot actually unload due to symbol references still being held.","solutions":["Make library unload idempotent: track closed state and skip closeLibrary for nil/already-closed handles.","Audit teardown paths for duplicate close calls (defer + explicit call).","If unloading is not essential to your use case, log and continue — the OS reclaims the library at process exit.","Update the baml Go bindings/native library if a linker quirk in your platform build is suspected."],"exampleFix":"// before\ndefer closeLibrary(handle)\n// ...\ncloseLibrary(handle) // second close -> \"dlclose failed\"\n\n// after\ndefer func() {\n    if handle != nil {\n        _ = closeLibrary(handle)\n        handle = nil\n    }\n}()","handlingStrategy":"try-catch","validationCode":"if handle == nil || alreadyClosed {\n    return nil\n}","typeGuard":"func closable(h unsafe.Pointer, closed bool) bool {\n    return h != nil && !closed\n}","tryCatchPattern":"if err := closeLibrary(handle); err != nil {\n    log.Printf(\"library unload skipped: %v\", err)\n}","preventionTips":["Centralize library load/unload in one component; never close from multiple call sites.","Avoid unloading during tests; load once per process.","Log the error but rely on process exit to reclaim the library."],"tags":["cgo","dynamic-linking","unix","resource-cleanup"],"backgroundTag":"dlclose-failed","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"}