fyne-io/fyne · critical

XGetVisualInfo failed\n

Error message

XGetVisualInfo failed\n

What it means

x11.c takes the EGL native visual id and calls XGetVisualInfo with VisualIDMask to obtain the X visual for window creation. If the X server has no visual with that id, the call returns NULL and the process prints 'XGetVisualInfo failed' and exits(1). The EGL and X stacks disagree about which visual to use.

Source

Thrown at internal/driver/mobile/app/x11.c:47

	};
	EGLConfig config;
	EGLint num_configs;
	if (!eglChooseConfig(e_dpy, attribs, &config, 1, &num_configs)) {
		fprintf(stderr, "eglChooseConfig failed\n");
		exit(1);
	}
	EGLint vid;
	if (!eglGetConfigAttrib(e_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
		fprintf(stderr, "eglGetConfigAttrib failed\n");
		exit(1);
	}

	XVisualInfo visTemplate;
	visTemplate.visualid = vid;
	int num_visuals;
	XVisualInfo *visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
	if (!visInfo) {
		fprintf(stderr, "XGetVisualInfo failed\n");
		exit(1);
	}

	Window root = RootWindow(x_dpy, DefaultScreen(x_dpy));
	XSetWindowAttributes attr;

	attr.colormap = XCreateColormap(x_dpy, root, visInfo->visual, AllocNone);
	if (!attr.colormap) {
		fprintf(stderr, "XCreateColormap failed\n");
		exit(1);
	}

	attr.event_mask = StructureNotifyMask | ExposureMask |
		ButtonPressMask | ButtonReleaseMask | ButtonMotionMask;
	Window win = XCreateWindow(
		x_dpy, root, 0, 0, w, h, 0, visInfo->depth, InputOutput,
		visInfo->visual, CWColormap | CWEventMask, &attr);
	XFree(visInfo);

View on GitHub (pinned to 8860ee95c3)

Solutions

  1. Run on an X server with standard 24-bit TrueColor visuals (check xdpyinfo | grep -A5 visuals)
  2. Start virtual X with adequate visuals: xvfb-run -a -s '-screen 0 1024x768x24' ./yourapp
  3. Force software Mesa so EGL picks visuals the server actually has: LIBGL_ALWAYS_SOFTWARE=1 ./yourapp
  4. Update Mesa/vendor driver to fix EGL/X visual mismatches
  5. Patch x11.c to fall back to the default visual when XGetVisualInfo finds nothing

Example fix

// before (x11.c): exit when no X visual matches the EGL visual id
XVisualInfo *visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
if (!visInfo) { fprintf(stderr, "XGetVisualInfo failed\n"); exit(1); }

// after: retry with the screen's default visual
XVisualInfo *visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
if (!visInfo) {
	visTemplate.visualid = XVisualIDFromVisual(DefaultVisual(x_dpy, DefaultScreen(x_dpy)));
	visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
	if (!visInfo) { exit(1); }
}
Defensive patterns

Strategy: validation

Validate before calling

func visualPreflight() error {
	out, err := exec.Command("sh", "-c", "xdpyinfo | grep -c 'TrueColor'").Output()
	if err != nil || strings.TrimSpace(string(out)) == "0" {
		return fmt.Errorf("X server has no TrueColor visuals; use 24-bit depth (xvfb -screen 0 1024x768x24)")
	}
	return nil
}

Prevention

When it happens

Trigger: EGL reports a native visual id that does not exist on the connected X server: Xvfb with a limited set of visuals, remote X displays, mismatched vendor EGL vs the server's visuals, or unusual depths (16-bit displays).

Common situations: Running under plain Xvfb or VNC without full 24-bit TrueColor; NVIDIA proprietary EGL over a remote/ssh-forwarded display; multi-monitor X servers with per-screen visuals.

Related errors


AI-assisted analysis of fyne-io/fyne@8860ee95c3 (2026-08-15). Data as JSON: /api/errors/2caff0b2d7668e4f. Report an issue: GitHub.