GraphiteEditor/Graphite · info

Footprint widget should return multiple rows

Error message

Footprint widget should return multiple rows

What it means

widgets is a fixed-length [LayoutGroup; 3] array (location, scale, resolution rows). split_last() on an array of statically known non-zero length always returns Some, so this .expect can never fire at runtime — it is a compile-time-known invariant expressed as an assertion. Its real job is to peel the resolution row off as the returned widget and store the location/scale rows in extra_widgets.

Source

Thrown at editor/src/messages/portfolio/document/node_graph/node_properties.rs:638

				.label("Resolution")
				.mode_range()
				.min(0.)
				.range_min(Some(1.))
				.range_max(Some(100.))
				.unit("%")
				.on_update(parameter_widgets_info.update_value(move |x: &NumberInput| {
					let resolution = (bounds * x.value.unwrap_or(100.) / 100.).as_uvec2().max((1, 1).into()).min((4000, 4000).into());

					let footprint = Footprint { resolution, ..footprint };
					TaggedValue::Footprint(footprint)
				}))
				.on_commit(commit_value)
				.widget_instance(),
		);
	}

	let widgets = [LayoutGroup::row(location_widgets), LayoutGroup::row(scale_widgets), LayoutGroup::row(resolution_widgets)];
	let (last, rest) = widgets.split_last().expect("Footprint widget should return multiple rows");
	*extra_widgets = rest.to_vec();
	last.clone()
}

pub fn transform_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widgets: &mut Vec<LayoutGroup>) -> LayoutGroup {
	let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;

	let mut location_widgets = start_widgets(&parameter_widgets_info);
	location_widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());

	let mut rotation_widgets = vec![TextLabel::new("").widget_instance()];
	add_blank_assist(&mut rotation_widgets);
	rotation_widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());

	let mut scale_widgets = vec![TextLabel::new("").widget_instance()];
	add_blank_assist(&mut scale_widgets);
	scale_widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());

View on GitHub (pinned to c507b35645)

Solutions

  1. Classify it as unreachable; no runtime fix is required.
  2. Replace with array destructuring (let [a, b, last] = widgets;) so emptiness becomes a compile-time error instead of a hidden runtime assumption.
  3. If the collection ever becomes dynamically sized, handle None explicitly rather than expecting.

Example fix

// before
let (last, rest) = widgets.split_last().expect("Footprint widget should return multiple rows");
*extra_widgets = rest.to_vec();
last.clone()

// after — length is statically known, no runtime panic possible
let [location, scale, resolution] = widgets;
*extra_widgets = vec![location, scale];
resolution
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Not reachable at runtime with the current three-element array literal. It could only panic if widgets were refactored into an empty array or a dynamically-built Vec whose length is not guaranteed.

Common situations: Developers finding this string in crash reports and hunting a bug that cannot exist; later refactors converting the array to a runtime Vec, which would newly make None possible.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/24174e0252cc6964. Report an issue: GitHub.