emilk/egui · error

failed to construct C string from string for gl proc address

Error message

failed to construct C string from string for gl proc address

What it means

eframe builds a glow::Context from a loader closure; for every GL function name glow passes in, eframe converts it with std::ffi::CString::new, which fails if the string contains an interior NUL byte ('\0'). Real GL function names ('glGetString', 'glGenBuffers', ...) are plain ASCII literals and can never contain NUL, so this expect is effectively a defensive assert: firing it means the name supplied to the loader was corrupted or came from a mismatched/patched glow.

Source

Thrown at crates/eframe/src/native/glow_integration.rs:227

        let mut glutin_window_context = unsafe {
            GlutinWindowContext::new(egui_ctx, winit_window_builder, native_options, event_loop)?
        };

        // Creates the window - must come before we create our glow context
        glutin_window_context.initialize_window(ViewportId::ROOT, event_loop)?;

        {
            let viewport = &glutin_window_context.viewports[&ViewportId::ROOT];
            let window = viewport.window.as_ref().unwrap(); // Can't fail - we just called `initialize_all_viewports`
            epi_integration::apply_window_settings(window, window_settings);
        }

        let gl = unsafe {
            profiling::scope!("glow::Context::from_loader_function");
            Arc::new(glow::Context::from_loader_function(|s| {
                let s = std::ffi::CString::new(s)
                    .expect("failed to construct C string from string for gl proc address");

                glutin_window_context.get_proc_address(&s)
            }))
        };

        let painter = egui_glow::Painter::new(
            gl,
            "",
            native_options.glow_options.shader_version,
            native_options.dithering,
        )?;

        Ok((glutin_window_context, painter))
    }

    fn init_run_state(
        &mut self,
        event_loop: &ActiveEventLoop,

View on GitHub (pinned to d802a982ce)

Solutions

  1. Report the panic upstream to egui with the full backtrace and glow/egui versions.
  2. Verify the glow and egui_glow versions come from the same release: cargo tree -p glow -p egui_glow.
  3. Audit any custom unsafe FFI code in your binary for memory corruption.
Defensive patterns

Strategy: try-catch

Try / catch

// Last-resort boundary for an eframe-internal panic:
let result = std::panic::catch_unwind(|| {
    eframe::run_native("app", options, Box::new(|cc| Box::new(App::new(cc))))
});
if result.is_err() {
    log::error!("renderer boot panicked; check glow/egui version skew");
}

Prevention

When it happens

Trigger: Calling run_native with the Glow renderer makes glow query many proc addresses through this closure. The panic only triggers if one of those names contains an embedded NUL byte, which stock glow never produces.

Common situations: Practically never observed. Theoretically reachable with version-skewed forks of glow/egui_glow that pass non-literal names, or with heap corruption caused by unrelated unsafe code in the process.

Related errors


AI-assisted analysis of emilk/egui@d802a982ce (2026-08-16). Data as JSON: /api/errors/c7266050ca52f3f3. Report an issue: GitHub.