a-b-street/abstreet · critical
error building program
Error message
error building program: {:?} What it means
During Prerender setup, the app compiles its embedded GLSL 300 shaders into a GPU program via glow. If program creation/linking fails, it panics with the glow error — the driver rejected the shaders, indicating an OpenGL/driver capability problem.
Solutions
- Update the graphics driver to one with solid OpenGL 3.x/GLSL 300 support
- Force up-to-date Mesa or vendor drivers (not legacy software renderers)
- Try LIBGL_ALWAYS_SOFTWARE=1 with a recent Mesa to rule out driver bugs
- Compare shader source (shaders/vertex_300.glsl, fragment_300.glsl) against the driver's supported GLSL version
Defensive patterns
Strategy: fallback
Validate before calling
// verify the context actually exposes GLSL 300 support before compiling
let ver = unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
eprintln!("GLSL version: {}", ver); Try / catch
match Program::new(...) {
Ok(p) => p,
Err(e) => { eprintln!("shader link failed: {:?}; update drivers or use software rendering", e); std::process::exit(1); }
} Prevention
- Keep GPU drivers updated; prefer vendor or recent Mesa drivers
- Log SHADING_LANGUAGE_VERSION at startup to catch capability gaps early
- Test on minimal/CI GPUs before releases
- Fallback to software rendering when linking fails
When it happens
Trigger: Building the program from vertex_300.glsl/fragment_300.glsl fails because the created context doesn't actually support GLSL #version 300 es / OpenGL 3.x features used by the shaders.
Common situations: Software/old Mesa drivers with incomplete GLSL 300 support; buggy GPU drivers that fail to link valid shaders; running on hardware below the required OpenGL version after the context check passed loosely.
Related errors
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/cbf7951208d97086.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/backend_glow_native.rs:54
let program = unsafe {
build_program(
&gl,
include_str!("../shaders/vertex_140.glsl"),
include_str!("../shaders/fragment_140.glsl"),
)
.or_else(|err| {
warn!(
"unable to build program with default shaderrs, falling back to v300. error: {:?}",
err
);
build_program(
&gl,
include_str!("../shaders/vertex_300.glsl"),
include_str!("../shaders/fragment_300.glsl"),
)
})
.unwrap_or_else(|err| {
panic!("error building program: {:?}", err);
})
};
(
PrerenderInnards::new(gl, true, program, Some(WindowAdapter(windowed_context))),
event_loop,
)
}
pub struct WindowAdapter(glutin::WindowedContext<glutin::PossiblyCurrent>);
impl WindowAdapter {
pub fn window(&self) -> &winit::window::Window {
self.0.window()
}
pub fn window_resized(&self, new_size: ScreenDims, scale_factor: f64) {
let physical_size = winit::dpi::LogicalSize::from(new_size).to_physical(scale_factor);View on GitHub (pinned to 0964f29315)