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
- 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.
- 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).
- 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.
- 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
- Register every ToolType variant in ToolData's constructor; use an exhaustive match on the enum so additions are compiler-flagged.
- Validate (and sanitize) restored active-tool state from preferences against the registered set.
- Add a startup assertion that the active tool resolves before any event dispatch.
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
- Star node can't be found
- Brush node does not exist
- Path node does not exist
- No min
- Cannot find connected anchor
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/e0a80f6f386a0c21.
Report an issue: GitHub.