emilk/egui · error
No fonts available until first call to Context::run()
Error message
No fonts available until first call to Context::run()
What it means
Context::fonts() gives read-write access to egui's Fonts via a closure, but fonts are only initialized during the first pass started by Context::run(). Before that, ctx.fonts is None and the expect panics. This is an initialization-order guard: font-dependent APIs are meaningless before the first frame.
Solutions
- Move the ctx.fonts() call into your frame callback (inside Context::run / eframe's update fn)
- Defer any text-metric-dependent setup until the first frame executes
- If you need fonts before the first frame, call Context::run (or begin_pass/end_pass) once beforehand
- In tests, use an initialized harness (e.g. run one pass) before asserting on fonts
Example fix
// before
let ctx = egui::Context::default();
let h = ctx.fonts(|f| f.layout_no_wrap("hi".into(), id, color)); // panics
// after
let ctx = egui::Context::default();
ctx.run(Instant::now(), |ctx| {
let h = ctx.fonts(|f| f.layout_no_wrap("hi".into(), id, color));
}); Defensive patterns
Strategy: validation
Validate before calling
// Rust: guard before querying fonts
if !ctx.will_discard() && has_run_once(ctx) {
ctx.fonts(|f| /* ... */);
} Type guard
fn fonts_available(ctx: &egui::Context) -> bool {
ctx.memory(|m| !m.areas.is_empty()) // implies at least one pass ran
} Prevention
- Only access fonts inside frame callbacks
- Never query fonts during app/Context construction
- Run one pass in tests before font assertions
- Cache font metrics after first frame instead of startup
When it happens
Trigger: Calling ctx.fonts(...) (write access variant, context.rs:1163) before the first Context::run()/BeginPass call, e.g. during backend setup, in a constructor, or in a test that builds a Context directly.
Common situations: Measuring text or querying font layout in app initialization code before the eframe update loop starts; unit tests constructing Context::default() and immediately reading fonts; plugins reading fonts in an init hook.
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 loaded
- 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/2026e2dd4fbb2365.
Report an issue: GitHub.
Appendix: source
Thrown at crates/egui/src/context.rs:1316
///
/// This is swapped at the end of each pass.
#[inline]
pub(crate) fn prev_pass_state<R>(&self, reader: impl FnOnce(&PassState) -> R) -> R {
self.write(move |ctx| reader(&ctx.viewport().prev_pass))
}
/// Read-only access to [`Fonts`].
///
/// Not valid until first call to [`Context::run_ui()`].
/// That's because since we don't know the proper `pixels_per_point` until then.
#[inline]
pub fn fonts<R>(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R {
self.write(move |ctx| {
let pixels_per_point = ctx.pixels_per_point();
reader(
&ctx.fonts
.as_mut()
.expect("No fonts available until first call to Context::run()")
.with_pixels_per_point(pixels_per_point),
)
})
}
/// Read-write access to [`Fonts`].
///
/// Not valid until first call to [`Context::run_ui()`].
/// That's because since we don't know the proper `pixels_per_point` until then.
#[inline]
pub fn fonts_mut<R>(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R {
self.write(move |ctx| {
let pixels_per_point = ctx.pixels_per_point();
reader(
&mut ctx
.fonts
.as_mut()
.expect("No fonts available until first call to Context::run()")View on GitHub (pinned to 8fb03c9ae9)