emilk/egui · error
No fonts loaded
Error message
No fonts loaded
What it means
In Context::tessellate (context.rs:3067), when the requested pixels_per_point has no exact font-size match, egui falls back to the first available font entry and expects at least one to exist. The panic 'No fonts loaded' means ctx.fonts is None or empty — fonts were never initialized because Context::run() has not run yet, so tessellation cannot proceed.
Solutions
- Ensure Context::run executes (at least one pass) before calling tessellate on shapes
- Register fonts explicitly via Context::set_fonts before tessellating outside the normal loop
- Tessellate the shapes returned within the same pass that produced them
- Check that your integration isn't re-creating the Context each frame, losing font state
Example fix
// before
let shapes = memory.shapes; // on a fresh Context
let prims = ctx.tessellate(shapes); // panics: no fonts loaded
// after
ctx.run(input, |ctx| {
let prims = ctx.tessellate(ctx draining shapes);
}); Defensive patterns
Strategy: validation
Validate before calling
// Rust: ensure fonts exist before tessellating let has_fonts = ctx.run(input, |ctx| ctx.tessellate(shapes)); // tessellate only post-run
Prevention
- Call tessellate only after at least one Context::run pass
- Call Context::set_fonts before off-loop tessellation
- Tessellate shapes within the same pass they were produced
- Avoid recreating the Context between shape collection and tessellation
When it happens
Trigger: Calling ctx.tessellate/shapes-to-primitives APIs before the first Context::run()/pass; rendering shapes collected outside the frame loop on a fresh Context.
Common situations: Custom integration code that tessellates egui shapes in its own render loop without running the egui context; rendering buffered shapes from a previous pass on a newly constructed Context; backend drawing paths invoked before egui's first update.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- No fonts available until first call to Context::run()
- Context::root_ui was called while the root Ui was already…
- Could not create Date
- Could not create Date
- Error parsing TTF/OTF font file
AI-assisted analysis of emilk/egui@8fb03c9ae9 (2026-09-12).
Data as JSON: /api/errors/cb915b73dbb9bbff.
Report an issue: GitHub.
Appendix: source
Thrown at crates/egui/src/context.rs:3222
shapes: Vec<ClippedShape>,
pixels_per_point: f32,
) -> Vec<ClippedPrimitive> {
profiling::function_scope!();
// A tempting optimization is to reuse the tessellation from last frame if the
// shapes are the same, but just comparing the shapes takes about 50% of the time
// it takes to tessellate them, so it is not a worth optimization.
self.write(|ctx| {
let tessellation_options = ctx.memory.options.tessellation_options;
let texture_atlas = if let Some(fonts) = ctx.fonts.as_ref() {
fonts.texture_atlas()
} else {
log::warn!("No font size matching {pixels_per_point} pixels per point found.");
ctx.fonts
.iter()
.next()
.expect("No fonts loaded")
.texture_atlas()
};
let paint_stats = PaintStats::from_shapes(&shapes);
let clipped_primitives = {
profiling::scope!("tessellator::tessellate_shapes");
tessellator::Tessellator::new(
pixels_per_point,
tessellation_options,
texture_atlas.size(),
texture_atlas.prepared_discs(),
)
.tessellate_shapes(shapes)
};
ctx.paint_stats = paint_stats.with_clipped_primitives(&clipped_primitives);
clipped_primitives
})
}View on GitHub (pinned to 8fb03c9ae9)