{"record":{"id":"33d396c8cf79070b","repo":"SeleniumHQ/selenium","slug":"failed-to-dlopen-s","errorCode":null,"errorMessage":"Failed to dlopen %s\n","messagePattern":"Failed to dlopen (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cpp/linux-specific/x_ignore_nofocus.c","lineNumber":640,"sourceCode":"  if (suitable_xlib_index >= 0) {\n    snprintf(library, MAX_LIBRARY_PATH, \"%s\", possible_locations[suitable_xlib_index]);\n    found_library = TRUE;\n  } else {\n    found_library = find_xlib_by_env(library, required_lib_arch);\n  }\n  if (found_library == FALSE) {\n    const char* desired_arch = (required_lib_arch == EM_386 ? \"32-bit\" : \"64-bit\");\n    fprintf(stderr, \"None of the following is a %s version of Xlib:\", desired_arch);\n    int i;\n    for (i = 0; i < locations_len; i++) {\n      fprintf(stderr, \" %s\\n\", possible_locations[i]);\n    }\n    return NULL;\n  }\n\n  ret_handle = dlopen(library, RTLD_LAZY);\n  if (ret_handle == NULL) {\n    fprintf(stderr, \"Failed to dlopen %s\\n\", library);\n    fprintf(stderr, \"dlerror says: %s\\n\", dlerror());\n  }\n\n  return ret_handle;\n}\n\nvoid print_event_to_log(Display* dpy, XEvent* ev)\n{\n#ifdef DEBUG_PRINTOUTS\n  if ((ev->type != PropertyNotify) && (ev->type != ConfigureNotify)) {\n    print_event(g_out_stream, ev, dpy);\n  }\n#endif\n}\n\n// This global variable is intentionally declared here - as I wish the rest\n// of the functions will act on it as a parameter.\nFocusKeepStatus g_focus_status;","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/cpp/linux-specific/x_ignore_nofocus.c#L622-L658","documentation":"stderr diagnostic from get_xlib_handle() emitted when dlopen(library, RTLD_LAZY) returns NULL after a candidate libX11 path was successfully located by arch or env. Unlike error 501 (library not found), here the file exists and has the right ELF machine type, but the dynamic loader refused to map it. The immediately following line prints dlerror() with the precise reason. The function still returns NULL, so the focus-prevention shim is disabled exactly as in the not-found case, but the fix is different: this is a shared-library dependency or permission problem, not a missing-library problem.","triggerScenarios":"dlopen() fails on a found libX11.so.6 inside get_xlib_handle() — most often because a transitive dependency (libxcb.so.1, libXau.so.6, libXdmcp.so.0, libdl.so.2, or a glibc symbol version) is missing or the wrong ABI; also when SELinux/AppArmor denies the load, the .so is corrupt or truncated, or there is a glibc-vs-musl mismatch (e.g. glibc-built helper loading a musl-system libX11).","commonSituations":"Slimmed Alpine/musl-based images (the helper is built against glibc); containers that installed libX11 but not libxcb1/libXau6; partial apt upgrades leaving libX11 without its runtime deps; SELinux enforcing mode blocking .so load; corrupt package install; multi-arch systems pulling the wrong libxcb alongside the right libX11.","solutions":["Read the next stderr line ('dlerror says: ...') for the exact loader error; it usually names the missing symbol or undefined library.","Run `ldd <path-from-the-message>` on the dlopened libX11.so.6 and install every dependency it reports as 'not found' (commonly `apt-get install -y libxcb1 libxau6 libxdmcp6`).","If on Alpine/musl, switch to a glibc-based image (or install gcompat) because the native helper is built against glibc and dlopen of a musl libX11 will fail at symbol resolution.","For SELinux denials, check `ausearch -m avc -ts recent` / `dmesg | grep -i selinux` and adjust the context or set the host to permissive for diagnosis; for a corrupt .so, `apt-get install --reinstall libx11-6`."],"exampleFix":"# before (libX11 present but dlopen fails: missing libxcb)\n# stderr:\n#   Failed to dlopen /usr/lib/x86_64-linux-gnu/libX11.so.6\n#   dlerror says: libxcb.so.1: cannot open shared object file\n\n# after\napt-get update && apt-get install -y libxcb1 libxau6\njava -jar selenium-server.jar   # dlopen succeeds, get_xlib_handle returns non-NULL","handlingStrategy":"validation","validationCode":"#!/usr/bin/env bash\n# Validate that the located libX11 can actually be loaded before launching Selenium.\nLIB=\"$(ldconfig -p | awk '/libX11\\.so\\.6$/ {print $NF; exit}')\"\n[ -n \"$LIB\" ] || { echo 'libX11.so.6 not in ldconfig cache'; exit 1; }\n\necho \"Checking $LIB\"\nldd \"$LIB\" | grep -i 'not found' && {\n  echo 'FAIL: libX11 has unresolved dependencies; install them (libxcb1, libxau6, ...)'\n  exit 1\n}\n\n# Probe an actual dlopen the way the helper will\npython3 - \"$LIB\" <<'PY' || { echo 'FAIL: dlopen rejected libX11'; exit 1; }\nimport sys, ctypes\nctypes.CDLL(sys.argv[1], mode=ctypes.RTLD_LAZY)\nprint('OK: dlopen succeeded')\nPY","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always install libX11's runtime dependencies alongside it (`apt-get install -y libx11-6 libxcb1 libxau6 libxdmcp6`), not just libX11 itself.","On Alpine/musl, use a glibc base image or gcompat; the native helper is glibc-built and dlopen of musl libs fails.","Run `ldd` on libX11.so.6 in your image build to catch missing transitive deps before runtime.","Keep SELinux/AppArmor policy permissive for the JVM loading native helpers, or label the .so correctly; check `dmesg`/`ausearch` when dlopen fails silently."],"tags":["linux","native","x11","libx11","dlopen","shared-library","selenium","dependencies"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}