{"record":{"id":"cf1a87319a9cb7be","repo":"influxdata/influxdb","slug":"catalog-records-must-be-structs-with-named-fields","errorCode":null,"errorMessage":"catalog records must be structs with named fields","messagePattern":"catalog records must be structs with named fields","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"influxdb3_catalog_macros/src/lib.rs","lineNumber":162,"sourceCode":"            shape: shape.base10_parse()?,\n            shape_span: shape.span(),\n            flags,\n        })\n    }\n}\n\nfn expand(metas: Punctuated<Meta, Token![,]>, item: ItemStruct) -> syn::Result<TokenStream2> {\n    let args = Args::parse(metas)?;\n\n    if !item.generics.params.is_empty() {\n        return Err(syn::Error::new(\n            item.generics.span(),\n            \"catalog records cannot be generic — the persisted bytes must be one fixed shape\",\n        ));\n    }\n\n    let Fields::Named(ref fields) = item.fields else {\n        return Err(syn::Error::new(\n            item.fields.span(),\n            \"catalog records must be structs with named fields\",\n        ));\n    };\n\n    let field_types: Vec<&Type> = fields.named.iter().map(|f| &f.ty).collect();\n    for ty in &field_types {\n        types::check(ty)?;\n    }\n\n    let actual = shape::fingerprint(&field_types);\n    if actual != args.shape {\n        return Err(syn::Error::new(\n            args.shape_span,\n            shape_mismatch_message(&item.ident, args.shape, actual),\n        ));\n    }\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_catalog_macros/src/lib.rs#L144-L180","documentation":"A compile-time error from the `#[catalog_record]` proc-macro. The macro only supports structs whose fields are all named (`struct Foo { a: u64 }`), because it reads field types in order to compute the persisted-shape fingerprint and generates code that accesses fields by name. Tuple structs, unit structs, and enum inputs are rejected.","triggerScenarios":"Applying `#[catalog_record(...)]` to a tuple struct (`struct Foo(u64)`), a unit struct (`struct Foo;`), or any non-struct item with unnamed fields. Raised in `expand` at the `let Fields::Named(ref fields) = item.fields else` branch.","commonSituations":"A developer models a record as a newtype wrapper or tuple struct for brevity, or ports a type from another serialization framework that allowed tuple structs.","solutions":["Convert the struct to use named fields (e.g. `struct Foo(u64)` becomes `struct Foo { field0: u64 }`).","If a newtype is desired, wrap it inside a named-field record struct instead.","Recompute the `shape` fingerprint after restructuring fields, since field order/types feed the fingerprint."],"exampleFix":"// before\n#[catalog_record(shape = 0x1234)]\nstruct Foo(u64);\n\n// after\n#[catalog_record(shape = 0x5678)]\nstruct Foo { id: u64 }","handlingStrategy":"validation","validationCode":"// Ensure the record struct uses named fields before applying the macro:\n// struct Foo { id: u64 }  // OK\n// struct Foo(u64);        // NOT OK","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always declare catalog records with named fields.","Avoid newtype/tuple-struct wrappers as records; wrap inside a named-field record.","Recompute the shape fingerprint when restructuring fields."],"tags":["proc-macro","compile-time","struct","serialization"],"backgroundTag":"invalid-argument-value","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}