emilk/egui · error
LayoutJob has no sections
Error message
LayoutJob has no sections
What it means
LayoutJob::format_at_byte resolves the TextFormat in effect at a byte offset by finding the section covering that range; it calls sections.last().expect("LayoutJob has no sections") purely as a fallback for indexes past the end. If the job has zero sections the expect panics — the documented precondition is that the job was built with at least one LayoutSection via LayoutJob::append.
Solutions
- Only call format_at_byte when !job.sections.is_empty(); check first and supply a default TextFormat otherwise
- Ensure every LayoutJob gets at least one append(...) call — even for empty text, append a zero-length default section
- Replace the expect with a graceful return of a default TextFormat when sections is empty
- If the job comes from library code that should never be empty, file/log the job's section count at the construction site to find where sections were dropped
Example fix
// before
let format = job.format_at_byte(ByteIndex(42));
// after
let format = if job.sections.is_empty() {
&TextFormat::default()
} else {
job.format_at_byte(ByteIndex(42))
}; Defensive patterns
Strategy: validation
Validate before calling
debug_assert!(!job.sections.is_empty(), "format_at_byte called on a LayoutJob with no sections");
Prevention
- Always append at least one section via LayoutJob::append, even for empty strings (zero-length default section)
- Guard custom widgets: check job.sections.is_empty() before per-byte format queries
- After deserializing or mutating a LayoutJob, assert it still has sections
- Return a default TextFormat for empty jobs in wrapper helpers instead of delegating blindly
When it happens
Trigger: Calling format_at_byte on a LayoutJob constructed empty (LayoutJob::default() or new()) or on a job whose sections were cleared/drained before layout; calling it during layout of a job where every append path was skipped (empty input string with no explicit default section).
Common situations: Custom text widgets that query per-byte formats on user-built jobs; rendering an empty string by appending no sections and then asking for formatting; refactors that build sections conditionally and end up with an empty vec; jobs deserialized or cached in an older format losing their sections.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Context::root_ui was called while the root Ui was already…
- Could not create Date
- Could not create Date
- failed to get current context to resize surface
- Harness::ui_id is only available for harnesses built with a…
AI-assisted analysis of emilk/egui@441971a776 (2026-09-12).
Data as JSON: /api/errors/47722846cc17ea3e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/epaint/src/text/text_layout_types.rs:230
return;
}
self.sections.push(LayoutSection {
leading_space,
byte_range,
format,
});
}
/// The [`TextFormat`] of the section containing the character starting at the given byte index.
///
/// If the index is past the end, the format of the last section is returned.
///
/// Panics if the job has no sections.
/// Assumes [`LayoutJob::sections`] are ordered by increasing `byte_range` (as produced by [`Self::append`]).
pub fn format_at_byte(&self, byte_idx: ByteIndex) -> &TextFormat {
self.debug_sanity_check();
let last = self.sections.last().expect("LayoutJob has no sections");
let idx = self
.sections
.partition_point(|section| section.byte_range.end <= byte_idx);
let section = self.sections.get(idx).unwrap_or(last);
§ion.format
}
/// Check the [`Self::sections`] invariant: the sections are ordered and together
/// cover the whole of [`Self::text`] with no gaps and no overlaps.
///
/// Only does anything in debug builds.
#[cfg_attr(not(debug_assertions), expect(clippy::unused_self))]
pub fn debug_sanity_check(&self) {
#[cfg(debug_assertions)]
{
if self.sections.is_empty() {
assert!(
self.text.is_empty(),View on GitHub (pinned to 441971a776)