{"record":{"id":"12e19f2ba7bf202d","repo":"linera-io/linera-protocol","slug":"derive-stableenum-does-not-yet-support-generic","errorCode":null,"errorMessage":"#[derive(StableEnum)] does not yet support generic enums","messagePattern":"#\\[derive\\(StableEnum\\)\\] does not yet support generic enums","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"linera-sdk-derive/src/stable_enum.rs","lineNumber":89,"sourceCode":"            .iter()\n            .find(|(_, t, _): &&(String, u32, &Variant)| *t == tag)\n        {\n            return Err(Error::new(\n                variant.span(),\n                format!(\n                    \"Keccak-256 tag collision between variants `{other_name}` and `{name}` \\\n                     (tag = {tag:#010x}). Rename one of the variants.\"\n                ),\n            ));\n        }\n        out.push((name, tag, variant));\n    }\n    Ok(out)\n}\n\nfn reject_generics(input: &ItemEnum) -> Result<()> {\n    if !input.generics.params.is_empty() || input.generics.where_clause.is_some() {\n        return Err(Error::new(\n            input.generics.span(),\n            \"#[derive(StableEnum)] does not yet support generic enums\",\n        ));\n    }\n    Ok(())\n}\n\n/// Emits the combined `Serialize` + `Deserialize` + `StableEnumTrace` impls.\npub fn generate_all(input: &ItemEnum, crate_root: CrateRoot) -> Result<TokenStream2> {\n    let ser = generate_serialize(input, &crate_root)?;\n    let de = generate_deserialize(input, &crate_root)?;\n    let tr = generate_trace(input, &crate_root)?;\n    Ok(quote! {\n        #ser\n        #de\n        #tr\n    })\n}","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-sdk-derive/src/stable_enum.rs#L71-L107","documentation":"`#[derive(StableEnum)]` generates serde Serialize/Deserialize impls keyed by per-variant tags computed from variant names; generic enums are explicitly unsupported because the tag scheme has no representation for type parameters. `reject_generics` fails compilation for any enum with type/lifetime parameters or a where clause.","triggerScenarios":"Deriving `StableEnum` on `enum E<T> { A(T), B }`, on an enum with a lifetime parameter, or on an enum carrying a `where` clause.","commonSituations":"Porting a generic state-machine enum to Linera's stable serialization; sharing one generic enum between an application contract and its Rust host/SDK code.","solutions":["Split the generic enum into concrete enums (one per payload type) and derive each.","Hoist the varying payload out of the enum: keep a non-generic StableEnum for the discriminant and store the payload alongside it in a struct.","If generics are essential, implement Serialize/Deserialize manually instead of using the derive.","For lifetime-only parameters, switch to owned data (`String`, `Vec<u8>`) so the enum is non-generic."],"exampleFix":"// before\n#[derive(StableEnum)]\nenum Message<T> { Set(T), Clear } // does not yet support generic enums\n\n// after\n#[derive(StableEnum)]\nenum MessageKind { Set, Clear }\nstruct Message<T> { kind: MessageKind, value: Option<T> }","handlingStrategy":"validation","validationCode":"// compile-time guard: StableEnum requires a non-generic enum\n// `cargo check` fails fast with 'does not yet support generic enums' — keep enums concrete","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't port generic serde enums into StableEnum verbatim; monomorphize first.","Model varying payloads as struct fields beside a non-generic discriminant enum.","Use owned types to eliminate lifetime parameters."],"tags":["proc-macro","stable-enum","compile-error","generics"],"backgroundTag":"derive-macro-error","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}