GraphiteEditor/Graphite · critical

The active tool is not initialized

Error message

The active tool is not initialized

What it means

ToolData::active_tool_mut fetches the currently active tool from the tools HashMap keyed by ToolType, panicking if active_tool_type names a tool that was never inserted. ToolData is the editor's tool dispatcher, so every mutable tool interaction (mouse/keyboard events sent to the active tool) funnels through this method. The expect therefore asserts a construction invariant: every ToolType value that can become active must have a registered Tool in the map before any event dispatch. It is violated when a new ToolType variant is added without registering its tool, or when active_tool_type is set from persisted/external input that bypasses registration.

Source

Thrown at editor/src/messages/tool/utility_types.rs:237

	}
	fn tool_type(&self) -> ToolType;
}

pub struct ToolData {
	pub active_tool_type: ToolType,
	pub active_shape_type: Option<ToolType>,
	pub tools: HashMap<ToolType, Box<Tool>>,
}

impl fmt::Debug for ToolData {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		f.debug_struct("ToolData").field("active_tool_type", &self.active_tool_type).field("tool_options", &"[…]").finish()
	}
}

impl ToolData {
	pub fn active_tool_mut(&mut self) -> &mut Box<Tool> {
		self.tools.get_mut(&self.active_tool_type).expect("The active tool is not initialized")
	}

	pub fn active_tool(&self) -> &Tool {
		self.tools.get(&self.active_tool_type).map(|x| x.as_ref()).expect("The active tool is not initialized")
	}
}

impl ToolData {
	pub fn send_layout(&self, responses: &mut VecDeque<Message>, layout_target: LayoutTarget, brush_tool: bool) {
		responses.add(LayoutMessage::SendLayout {
			layout: self.layout(brush_tool),
			layout_target,
		});
	}

	fn layout(&self, brush_tool: bool) -> Layout {
		let active_tool = self.active_shape_type.unwrap_or(self.active_tool_type);

View on GitHub (pinned to c507b35645)

Solutions

  1. Ensure the tool registration covers every ToolType variant: assert tools.len() == number of variants (or use a match that forces exhaustive registration) when building ToolData.
  2. On startup, validate that tools.contains_key(&active_tool_type) before entering the message loop and fall back to a known-registered default (e.g., Select).
  3. When adding a new tool, register it in the same commit as the enum variant; run the editor and cycle through all tools once in CI smoke tests.
  4. If preferences can restore an active tool, sanitize the stored value against the registered set before assigning.

Example fix

// before
pub fn active_tool_mut(&mut self) -> &mut Box<Tool> {
	self.tools.get_mut(&self.active_tool_type).expect("The active tool is not initialized")
}

// after
pub fn active_tool_mut(&mut self) -> &mut Box<Tool> {
	self.tools.get_mut(&self.active_tool_type).unwrap_or_else(|| panic!("ToolType {:?} has no registered tool; register it in ToolData::new", self.active_tool_type))
}
Defensive patterns

Strategy: validation

Validate before calling

// Before entering the message loop / dispatching to tools
if !tool_data.tools.contains_key(&tool_data.active_tool_type) {
	tool_data.active_tool_type = ToolType::Select; // known-registered fallback
}
let tool = tool_data.active_tool_mut();

Type guard

fn active_tool_ready(tool_data: &ToolData) -> bool {
	tool_data.tools.contains_key(&tool_data.active_tool_type)
}

Prevention

When it happens

Trigger: Any message-dispatch path that calls tool_data.active_tool_mut() — e.g., pointer/keyboard events routed to the active tool — after active_tool_type was set to a ToolType for which tools.get_mut returns None (unregistered variant or tool map not yet populated at startup).

Common situations: Adding a ToolType enum variant and forgetting the matching insert in ToolData construction; reordering initialization so active_tool_type defaults before the tools map is filled; restoring a persisted active tool from preferences that this build no longer registers; tests constructing ToolData manually without all tools.

Related errors


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