{"record":{"id":"d2d684b415b9bb71","repo":"cilium/cilium","slug":"type-s-is-not-a-struct","errorCode":null,"errorMessage":"type %s is not a struct","messagePattern":"type (.+?) is not a struct","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/alignchecker/alignchecker.go","lineNumber":150,"sourceCode":"\t_memberOffsets(members, offsets, 0, \"\")\n\treturn offsets\n}\n\nfunc check(name string, toCheck []any, structs map[string]*structInfo, checkOffsets bool) error {\n\tfor _, i := range toCheck {\n\t\tc, found := structs[name]\n\t\tif !found {\n\t\t\treturn fmt.Errorf(\"could not find C struct %s\", name)\n\t\t}\n\n\t\tg := reflect.TypeOf(i)\n\t\tif g == nil {\n\t\t\treturn fmt.Errorf(\"nil interface passed for type %s\", name)\n\t\t}\n\n\t\t// Input type must be a struct.\n\t\tif g.Kind() != reflect.Struct {\n\t\t\treturn fmt.Errorf(\"type %s is not a struct\", name)\n\t\t}\n\n\t\tif bs, rs := binary.Size(i), int(g.Size()); bs != rs {\n\t\t\treturn fmt.Errorf(\"type %s's binary.Size (%d) does not equal its unsafe.Sizeof (%d) size (struct with implicit trailing padding?)\", g.Name(), bs, rs)\n\t\t}\n\n\t\tif c.size != uint32(g.Size()) {\n\t\t\treturn fmt.Errorf(\"%s(%d) size does not match %s(%d)\", g, g.Size(),\n\t\t\t\tname, c.size)\n\t\t}\n\n\t\tif !checkOffsets {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor field := range g.Fields() {\n\t\t\tfieldName := field.Tag.Get(\"align\")\n\t\t\t// Ignore fields without `align` struct tag","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/alignchecker/alignchecker.go#L132-L168","documentation":"check() requires each supplied Go value to be a struct kind, since alignment comparison is defined over struct layouts. If the reflected Kind is anything else (pointer handled per API contract, slice, int, etc.), it errors that the type is not a struct.","triggerScenarios":"Passing a non-struct Go value (e.g. an integer, slice, or a named type wrapping a non-struct) in toCheck instead of a Go struct mirroring the C struct.","commonSituations":"Tests written against scalar fields rather than whole structs; refactors replacing a struct with a type alias to a non-struct; confused typedefs where the Go mirror is a basic type.","solutions":["Supply a Go struct type whose fields (and `align:` tags) mirror the C struct.","Dereference or unwrap wrappers: use the struct value, not a named non-struct type.","Check the test's toCheck literals for wrong types after API changes."],"exampleFix":"// before\ntoCheck[\"ct_key4\"] = []any{uint32(0)} // not a struct\n// after\ntoCheck[\"ct_key4\"] = []any{CtKey4{}} // Go struct mirror","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func allStructs(vals []any) bool {\n    for _, v := range vals {\n        t := reflect.TypeOf(v)\n        if t == nil || t.Kind() != reflect.Struct {\n            return false\n        }\n    }\n    return true\n}\n// call before CheckStructAlignments","tryCatchPattern":"if err := alignchecker.CheckStructAlignments(obj, toCheck, true); err != nil {\n    if strings.Contains(err.Error(), \"is not a struct\") {\n        t.Fatalf(\"toCheck entries must be Go structs mirroring C structs: %v\", err)\n    }\n    t.Fatal(err)\n}","preventionTips":["Provide full Go struct mirrors of C structs in alignchecker tests, never scalars.","Mirror every C struct field and add `align:` tags for the fields you assert.","Re-check Go mirrors after C-side struct changes."],"tags":["go","alignchecker","reflection","struct-layout"],"backgroundTag":"go-type-not-struct","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}