{"record":{"id":"0bfdac08c42836d5","repo":"GraphiteEditor/Graphite","slug":"validation-error-e","errorCode":null,"errorMessage":"Validation error:\n{e}","messagePattern":"Validation error:\n(.+?)","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"node-graph/node-macro/src/parsing.rs","lineNumber":1029,"sourceCode":"}\n\nfn parse_output(output: &ReturnType) -> syn::Result<Type> {\n\tmatch output {\n\t\tReturnType::Default => Ok(syn::parse_quote!(())),\n\t\tReturnType::Type(_, ty) => Ok((**ty).clone()),\n\t}\n}\n\nfn extract_attribute<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> {\n\tattrs.iter().find(|attr| attr.path().is_ident(name))\n}\n\n// Modify the new_node_fn function to use the code generation\npub fn new_node_fn(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> {\n\tlet crate_ident = CrateIdent::default();\n\tlet mut parsed_node = parse_node_fn(attr, item.clone()).map_err(|e| Error::new(e.span(), format!(\"Failed to parse node function:\\n{e}\")))?;\n\tparsed_node.replace_impl_trait_in_input();\n\tcrate::validation::validate_node_fn(&parsed_node).map_err(|e| Error::new(e.span(), format!(\"Validation error:\\n{e}\")))?;\n\tgenerate_node_code(&crate_ident, &parsed_node).map_err(|e| Error::new(e.span(), format!(\"Failed to generate node code:\\n{e}\")))\n}\n\nimpl ParsedNodeFn {\n\t/// The node's primary: the first argument (non-environment) field, whose declared shape classifies the node\n\t/// as an element-wise kernel, aggregation, or generator. Returns the field with its index in `fields`.\n\tpub(crate) fn primary_input_field(&self) -> Option<(usize, &ParsedField)> {\n\t\tself.fields.iter().enumerate().find(|(_, field)| !field.is_environment())\n\t}\n\n\tpub fn replace_impl_trait_in_input(&mut self) {\n\t\tif let Type::ImplTrait(impl_trait) = self.input.ty.clone() {\n\t\t\tlet ident = Ident::new(\"_Input\", impl_trait.span());\n\t\t\tlet mut bounds = impl_trait.bounds;\n\t\t\tbounds.push(parse_quote!('n));\n\t\t\tself.fn_generics.push(GenericParam::Type(TypeParam {\n\t\t\t\tattrs: Default::default(),\n\t\t\t\tident: ident.clone(),","sourceCodeStart":1011,"sourceCodeEnd":1047,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/node-graph/node-macro/src/parsing.rs#L1011-L1047","documentation":"Emitted when validate_node_fn rejects a node function that parsed successfully — semantic rules rather than syntax. The validator set covers implementations for generics, primary-input exposure, min/max usage, slider bounds, Item<T> parameter pairing, element-wise structure, and ranked inputs. Most current validators report via proc-macro-error's emit_error! with their own messages, so this wrapper text is the hard-failure path of validate_node_fn.","triggerScenarios":"A parsed node whose shape violates the rules: an Item<T> parameter on a node whose primary input is not ranked (Item<T>, List<T>, or ListDyn); #[implementations(...)] on a ranked parameter containing non-bare element types; generic type parameters without implementations when skip_impl is not set; invalid min/max or slider-bound attribute combinations.","commonSituations":"Adding a per-element (Item<T>) parameter to a node whose primary input is a plain value; forgetting #[implementations(...)] on a newly introduced generic parameter; converting an aggregation node to a generator while leaving ranked parameters behind.","solutions":["Read the validator text after the header — it names the rule and the offending parameter","Give Item<T> parameters a ranked primary input (Item<T>, List<T>, or ListDyn), or drop the Item wrapper","Add #[implementations(...)] for every generic parameter, or opt out with skip_impl when implementations are registered manually","Check min/max and slider-bound attributes against their constraints"],"exampleFix":"// before: Item<T> parameter but an unranked primary input\n#[node_macro::node(category(\"Color\"))]\nfn blend(base: f64, #[implementations(f32, f64)] each: Item<f64>) -> f64 { /* ... */ }\n\n// after: make the primary input ranked so the frame matches\n#[node_macro::node(category(\"Color\"))]\nfn blend(base: List<f64>, #[implementations(f32, f64)] each: Item<f64>) -> f64 { /* ... */ }","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model new nodes on existing element-wise, aggregation, or generator nodes with the same shape","Give Item<T> parameters a ranked primary input (Item<T>, List<T>, ListDyn)","Declare #[implementations(...)] for every generic parameter up front, or use skip_impl deliberately"],"tags":["proc-macro","rust","node-graph","compile-time","validation"],"backgroundTag":"proc-macro-validation-error","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}