influxdata/influxdb · error · syn::Error
⚠ Field shape of catalog record
Error message
⚠ Field shape of catalog record ({ident}) changed ⚠
Declared shape:
{declared:#010x}
Actual shape:
{actual:#010x}
The fingerprint covers the field types, in order — adding, removing, reordering, or retyping a field moves it. Field renames do not, because bitcode does not encode field names.
Once a catalog record type has been shipped in a released version of the software, it cannot be modified. To introduce new functionality, add a new record type.
If this is the first time you're adding this record type, or are making modifications to it prior to releasing it, update the `shape` argument to the actual value above.
What it means
A compile-time guard from the `#[catalog_record]` macro. The macro computes a fingerprint (via `shape::fingerprint`) over the record's field types in order and compares it with the `shape = 0x...` argument. A mismatch means the field layout (added/removed/reordered/retyped fields — renames don't count, bitcode doesn't encode names) differs from the declared persisted shape, which would silently corrupt previously written catalog bytes.
Solutions
- If this is the first release of the record type (or changes are pre-release), update the `shape` argument to the actual fingerprint printed in the error message.
- If the record type shipped in a released version, revert the field change; never modify it.
- To add new functionality, define a NEW record type with its own shape instead of editing the existing one.
Example fix
// before (added a field but kept old shape)
#[catalog_record(shape = 0x12345678)]
struct Foo { id: u64, name: String }
// after
#[catalog_record(shape = 0x9abcdef0)]
struct Foo { id: u64, name: String } Defensive patterns
Strategy: validation
Validate before calling
// Before changing a shipped record's fields, check compatibility: // 1. Only append via a NEW record type if the old one was released. // 2. If pre-release, copy the 'Actual shape' hex from the error into `shape = 0x...`.
Prevention
- Treat released catalog record types as frozen; add new record types for new functionality.
- Never reorder or retype existing fields; renames are safe but still re-verify.
- After any field edit pre-release, update `shape` to the fingerprint printed in the error.
- Include the compile check in CI so shape drift is caught on PRs.
When it happens
Trigger: Modifying the fields of a struct annotated with `#[catalog_record(shape = X)]` (adding, removing, reordering, or changing a field's type) without updating the `shape` argument. Raised in `expand` when `actual != args.shape`.
Common situations: A developer adds a new field to an already-released catalog record, reorders fields for tidiness, or changes `u32` to `u64` — all during a routine refactor of shipped code.
Related errors
- catalog records cannot be generic — the persisted bytes…
- catalog records must be structs with named fields
- ` ` is a qualified path. A catalog record may only hold…
- ` ` is not allowed in a catalog record. Fields may be…
- ` ` is generic. Only may take type parameters in a catalog…
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/61d340b27a0eb99f.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_catalog_macros/src/lib.rs:175
"catalog records cannot be generic — the persisted bytes must be one fixed shape",
));
}
let Fields::Named(ref fields) = item.fields else {
return Err(syn::Error::new(
item.fields.span(),
"catalog records must be structs with named fields",
));
};
let field_types: Vec<&Type> = fields.named.iter().map(|f| &f.ty).collect();
for ty in &field_types {
types::check(ty)?;
}
let actual = shape::fingerprint(&field_types);
if actual != args.shape {
return Err(syn::Error::new(
args.shape_span,
shape_mismatch_message(&item.ident, args.shape, actual),
));
}
let ident = &item.ident;
let id = &args.id;
let flags = args
.flags
.map(|f| quote!(#f))
.unwrap_or_else(|| quote!(crate::format::RecordFlags::none()));
Ok(quote! {
#[derive(
Debug,
Clone,
PartialEq,
Eq,View on GitHub (pinned to 06200ef96b)