{"record":{"id":"9dc02369277b2077","repo":"cilium/cilium","slug":"external-types-needed-but-types-package-is-empty","errorCode":null,"errorMessage":"external types needed but types package is empty","messagePattern":"external types needed but types package is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/dpgen/config.go","lineNumber":66,"sourceCode":"\ts, err := varsToStruct(spec, configOpts.outName, configOpts.kind, configOpts.typesPkg, configOpts.embeds)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"generating config struct: %w\", err)\n\t}\n\n\tif needUtils {\n\t\tif err := writeUtilFile(\"util_generated.go\", configOpts.goPkg); err != nil {\n\t\t\treturn fmt.Errorf(\"writing util file: %w\", err)\n\t\t}\n\t}\n\n\tvar b bytes.Buffer\n\tif err := writeHeader(&b, configOpts.goPkg, nil); err != nil {\n\t\treturn fmt.Errorf(\"writing header: %w\", err)\n\t}\n\n\tif needExternalTypes {\n\t\tif configOpts.typesPkg == \"\" {\n\t\t\treturn fmt.Errorf(\"external types needed but types package is empty\")\n\t\t}\n\t\tif err := writeImports(&b, []string{configOpts.typesPkg}); err != nil {\n\t\t\treturn fmt.Errorf(\"writing imports: %w\", err)\n\t\t}\n\t}\n\tif _, err := b.WriteString(s); err != nil {\n\t\treturn fmt.Errorf(\"writing struct: %w\", err)\n\t}\n\tif err := os.WriteFile(configOpts.outFile, b.Bytes(), 0644); err != nil {\n\t\treturn fmt.Errorf(\"writing output file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//go:embed util_generated.go.tpl\nvar utilTpl string\n","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/tools/dpgen/config.go#L48-L84","documentation":"dpgen detected that the config struct references external struct/union types (needExternalTypes was set because a config variable is a struct or union that must be rendered separately by `dpgen type`), but the --types-pkg flag was not provided, so the generated import for the types package would be empty. Generation aborts rather than emitting code that references types from an unknown package.","triggerScenarios":"Running `dpgen config` on an object whose DECLARE_CONFIG variables include a struct- or union-typed variable while omitting --types-pkg; configOpts.typesPkg is the empty string when btfVarGoTypeName hit a *btf.Struct or *btf.Union case.","commonSituations":"Someone adds a new struct-typed config variable to the eBPF datapath but doesn't know dpgen now requires the types package; copying an older dpgen invocation line that predates struct-typed config support; wiring dpgen in a build script with hardcoded flags that lack --types-pkg.","solutions":["Pass --types-pkg pointing at the Go package that will contain the generated types, e.g. --types-pkg github.com/cilium/cilium/pkg/datapath/config/types","Also run `dpgen type` for each referenced struct/union so the types package actually contains those types","Regenerate the dpgen invocation in the Makefile/build script to include the flag once any struct-typed config exists","If no struct/union config variables are intended, change the offending variable to a scalar type so needExternalTypes stays false"],"exampleFix":"// before\ndpgen config bpf_bpf_node_config.o node_config.go --out-name NodeConfig --kind \"cilium.io/v2:NodeConfig\"\n// after\ndpgen config bpf_bpf_node_config.o node_config.go --out-name NodeConfig --kind \"cilium.io/v2:NodeConfig\" --types-pkg github.com/cilium/cilium/pkg/datapath/config/types","handlingStrategy":"validation","validationCode":"# Fail early if struct-typed config vars exist but --types-pkg is absent\ngrep -Eq 'volatile const struct|volatile const union' bpf/*.c \\\n  && ! echo \"$DPGEN_FLAGS\" | grep -q -- --types-pkg \\\n  && { echo \"struct-typed config variables require --types-pkg\"; exit 1; }","typeGuard":null,"tryCatchPattern":"if err := runConfig(cmd, args); err != nil {\n\tif strings.Contains(err.Error(), \"types package is empty\") {\n\t\tfmt.Fprintln(os.Stderr, \"add --types-pkg <go/import/path> to the dpgen config invocation\")\n\t\tos.Exit(2)\n\t}\n\tfmt.Fprintf(os.Stderr, \"%v\\n\", err)\n\tos.Exit(1)\n}","preventionTips":["Always include --types-pkg in dpgen config invocations in Makefiles when any config variable is a struct or union","Run `dpgen type` for each referenced struct/union into the same types package","Centralize dpgen flags in one Makefile variable so they stay consistent","When adding a struct-typed config variable, update the generator wiring in the same change"],"tags":["codegen","cli-flag","ebpf","configuration"],"backgroundTag":"missing-required-flag","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}