{"record":{"id":"0a45af70186b4dc2","repo":"GraphiteEditor/Graphite","slug":"failed-to-create-artboard-node","errorCode":null,"errorMessage":"Failed to create artboard node","messagePattern":"Failed to create artboard node","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"editor/src/messages/portfolio/document/document_message_handler.rs","lineNumber":1659,"sourceCode":"\t\t\t\t// Get bounding box of all layers (always needed to confirm there is content)\n\t\t\t\tlet bounds = self.network_interface.document_bounds_document_space(false);\n\t\t\t\tlet Some(bounds) = bounds else { return };\n\n\t\t\t\t// When artboard_canvas is provided (SVG file-open flow), use the declared canvas origin and dimensions;\n\t\t\t\t// no content-shift Transform node needed since the SVG was already placed at its natural coordinates.\n\t\t\t\tlet (artboard_location, artboard_dimensions, content_shift) = if let Some((origin, dimensions)) = artboard_canvas {\n\t\t\t\t\t(origin.as_dvec2(), dimensions.as_dvec2(), DVec2::ZERO)\n\t\t\t\t} else {\n\t\t\t\t\t// No declared canvas (image or clipboard paste): derive location and dimensions from the content bounding box.\n\t\t\t\t\tlet location = if place_artboard_at_origin { DVec2::ZERO } else { bounds[0].round() };\n\t\t\t\t\t(location, (bounds[1] - bounds[0]).round(), -bounds[0].round())\n\t\t\t\t};\n\n\t\t\t\t// Create an artboard and set its dimensions to the bounding box size and location\n\t\t\t\tlet node_id = NodeId::new();\n\t\t\t\tlet node_layer_id = LayerNodeIdentifier::new_unchecked(node_id);\n\t\t\t\tlet new_artboard_node = document_node_definitions::resolve_network_node_type(\"Artboard\")\n\t\t\t\t\t.expect(\"Failed to create artboard node\")\n\t\t\t\t\t.default_node_template();\n\t\t\t\tresponses.add(NodeGraphMessage::InsertNode {\n\t\t\t\t\tnode_id,\n\t\t\t\t\tnode_template: Box::new(new_artboard_node),\n\t\t\t\t});\n\t\t\t\tlet needs_content_transform = !content_shift.abs_diff_eq(DVec2::ZERO, 1e-6);\n\t\t\t\t// With a content Transform node: shift by the layer indent plus the node width. Without: use just the layer indent.\n\t\t\t\tresponses.add(NodeGraphMessage::ShiftNodePosition {\n\t\t\t\t\tnode_id,\n\t\t\t\t\tx: if needs_content_transform { LAYER_INDENT_OFFSET + NODE_CHAIN_WIDTH } else { LAYER_INDENT_OFFSET },\n\t\t\t\t\ty: -3,\n\t\t\t\t});\n\t\t\t\tresponses.add(GraphOperationMessage::ResizeArtboard {\n\t\t\t\t\tlayer: LayerNodeIdentifier::new_unchecked(node_id),\n\t\t\t\t\tlocation: artboard_location,\n\t\t\t\t\tdimensions: artboard_dimensions,\n\t\t\t\t});\n","sourceCodeStart":1641,"sourceCodeEnd":1677,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/document_message_handler.rs#L1641-L1677","documentation":"Panic when document_node_definitions::resolve_network_node_type(\"Artboard\") returns None. This function looks the identifier up in the DOCUMENT_NODE_TYPES registry compiled into the editor from the node definitions list. The message fires while creating an artboard for newly imported content (e.g., pasting an image with no declared canvas), so a missing 'Artboard' entry in the registry means the build's node definitions are incomplete or out of sync with the calling code.","triggerScenarios":"Building the workspace with crates at mismatched versions so the editor references a node the registry crate does not contain; the Artboard node definition being renamed, feature-gated, or removed in a fork; stale incremental build artifacts after definitions changed.","commonSituations":"Refactors that rename the node identifier string without updating this call site; custom builds that prune standard node definitions; cargo builds after switching branches where node-graph crates changed; forks that disable the Artboard node.","solutions":["Search document_node_definitions.rs for the node registered under identifier \"Artboard\" and restore/rename it back","cargo clean and rebuild the whole workspace together so the registry and callers are consistent","If the node was intentionally removed/renamed, update this call site to the new identifier","Check any feature flags that conditionally exclude node definitions from the registry"],"exampleFix":"// before\nlet new_artboard_node = document_node_definitions::resolve_network_node_type(\"Artboard\")\n\t.expect(\"Failed to create artboard node\")\n\t.default_node_template();\n\n// after\nlet Some(artboard_definition) = document_node_definitions::resolve_network_node_type(\"Artboard\") else {\n\ttracing::error!(\"Artboard node type missing from the document node registry\");\n\treturn;\n};\nlet new_artboard_node = artboard_definition.default_node_template();","handlingStrategy":"validation","validationCode":"// At startup or in tests, assert the registry actually contains the nodes the handlers depend on\n#[test]\nfn artboard_node_registered() {\n\tassert!(document_node_definitions::resolve_network_node_type(\"Artboard\").is_some(),\n\t\t\"'Artboard' node missing from DOCUMENT_NODE_TYPES; definitions and callers are out of sync\");\n}","typeGuard":"fn artboard_definition() -> Option<&'static document_node_definitions::DocumentNodeDefinition> {\n\tdocument_node_definitions::resolve_network_node_type(\"Artboard\")\n}","tryCatchPattern":null,"preventionTips":["Add a regression test asserting required node identifiers ('Artboard', etc.) resolve after any registry refactor","Rebuild the whole workspace together after changing node definitions to avoid version skew","Centralize node identifier strings as constants shared between definitions and call sites"],"tags":["rust","editor","node-registry","invariant","artboard"],"backgroundTag":"registry-lookup-missed","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}