A panic occurs when an embedded/inline field is a type alias and Alias types are enabled in Go.
To reproduce on the main branch:
- Apply the following example patch in controller-tools repository testdata:
diff --git a/pkg/crd/testdata/cronjob_types.go b/pkg/crd/testdata/cronjob_types.go
index e81a28ac..c6e16ab1 100644
--- a/pkg/crd/testdata/cronjob_types.go
+++ b/pkg/crd/testdata/cronjob_types.go
@@ -372,6 +372,9 @@ type CronJobSpec struct {
// This tests that selectable field.
SelectableFieldString string `json:"selectableFieldString,omitempty"`
+
+ // This tests that embedded struct, which is an alias type, is handled correctly.
+ InlineAlias `json:",inline"`
}
type StringAlias = string
@@ -380,6 +383,14 @@ type StringAlias = string
// +kubebuilder:validation:MaxLength=255
type StringAliasWithValidation = string
+type InlineAlias = EmbeddedStruct
+
+// EmbeddedStruct is for testing that embedded struct is handled correctly when it is used through an alias type.
+type EmbeddedStruct struct {
+ // FromEmbedded is a field from the embedded struct that was used through an alias type.
+ FromEmbedded string `json:"fromEmbedded,omitempty"`
+}
+
type ContainsNestedMap struct {
InnerMap map[string]string `json:"innerMap,omitempty"`
}
- Make sure Alias types are enabled, then run generate
$ go version
go version go1.23.2 linux/amd64
$ cd pkg/crd/testdata
$ GODEBUG=gotypesalias=1 go generate
The output will be following
panic: interface conversion: *types.Struct is not interface { Obj() *types.TypeName }: missing method Obj
goroutine 1 [running]:
sigs.k8s.io/controller-tools/pkg/crd.localNamedToSchema(0xc0012a76e0, 0xc00057e180)
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:285 +0x3eb
sigs.k8s.io/controller-tools/pkg/crd.typeToSchema(0xc0012a76e0, {0xeb9220, 0xc00057e180})
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:206 +0xd9
sigs.k8s.io/controller-tools/pkg/crd.structToSchema(0xc004e2fe70, 0xc00068fc38)
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:463 +0x872
sigs.k8s.io/controller-tools/pkg/crd.typeToSchema(0xc004e2fe70, {0xeb91f0, 0xc00068fc38})
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:216 +0x93
sigs.k8s.io/controller-tools/pkg/crd.infoToSchema(0xc0063d3e70)
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:125 +0xc5
sigs.k8s.io/controller-tools/pkg/crd.(*Parser).NeedSchemaFor(0xc000138960, {0xc00040bbe0, {0xc000809bb0, 0xb}})
/home/tsaarni/work/controller-tools/pkg/crd/parser.go:193 +0x290
sigs.k8s.io/controller-tools/pkg/crd.(*schemaContext).requestSchema(0xc0004616a0?, {0x0?, 0xd66e93?}, {0xc000809bb0?, 0x0?})
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:108 +0xdb
sigs.k8s.io/controller-tools/pkg/crd.localNamedToSchema(0xc006b08810, 0xc0005b5b60)
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:291 +0x4ae
sigs.k8s.io/controller-tools/pkg/crd.typeToSchema(0xc006b08810, {0xeb9220, 0xc0005b5b60})
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:206 +0xd9
sigs.k8s.io/controller-tools/pkg/crd.structToSchema(0xc004e30650, 0xc00012d140)
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:463 +0x872
sigs.k8s.io/controller-tools/pkg/crd.typeToSchema(0xc004e30650, {0xeb91f0, 0xc00012d140})
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:216 +0x93
sigs.k8s.io/controller-tools/pkg/crd.infoToSchema(0xc0063d4650)
/home/tsaarni/work/controller-tools/pkg/crd/schema.go:125 +0xc5
sigs.k8s.io/controller-tools/pkg/crd.(*Parser).NeedSchemaFor(0xc000138960, {0xc00040bbe0, {0xc0006176c4, 0x7}})
/home/tsaarni/work/controller-tools/pkg/crd/parser.go:193 +0x290
sigs.k8s.io/controller-tools/pkg/crd.(*Parser).NeedFlattenedSchemaFor(0xc000138960, {0xc00040bbe0, {0xc0006176c4, 0x7}})
/home/tsaarni/work/controller-tools/pkg/crd/parser.go:205 +0xcd
sigs.k8s.io/controller-tools/pkg/crd.(*Parser).NeedCRDFor(0xc000138960, {{0xc0008077ae, 0x17}, {0xc0006176c4, 0x7}}, 0x0)
/home/tsaarni/work/controller-tools/pkg/crd/spec.go:93 +0x57a
sigs.k8s.io/controller-tools/pkg/crd.Generator.Generate({0xc000016bd0, 0xc000016be0, 0x0, {0x0, 0x0, 0x0}, 0x0, {0x0, 0x0}, {0x0, ...}, ...}, ...)
/home/tsaarni/work/controller-tools/pkg/crd/gen.go:182 +0x566
sigs.k8s.io/controller-tools/pkg/genall.(*Runtime).Run(0xc00033bb90)
/home/tsaarni/work/controller-tools/pkg/genall/genall.go:272 +0x234
main.main.func1(0xc00048e300?, {0xc0002fbcb0?, 0x4?, 0xd64fa0?})
/home/tsaarni/work/controller-tools/cmd/controller-gen/main.go:176 +0x6a
github.com/spf13/cobra.(*Command).execute(0xc0002d4c08, {0xc000136090, 0x3, 0x3})
/home/tsaarni/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:985 +0xaaa
github.com/spf13/cobra.(*Command).ExecuteC(0xc0002d4c08)
/home/tsaarni/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1117 +0x3ff
github.com/spf13/cobra.(*Command).Execute(...)
/home/tsaarni/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1041
main.main()
/home/tsaarni/work/controller-tools/cmd/controller-gen/main.go:200 +0x2f6
exit status 2
cronjob_types.go:19: running "../../../.run-controller-gen.sh": exit status 1
When running GODEBUG=gotypesalias=0 go generate or just go generate there will not be panic. I assume this is because of Go language level in go.mod.
FYI: Interestingly, I found the issue while running controller-gen in another project using go run sigs.k8s.io/controller-tools/cmd/controller-gen ... with go1.23.x. However, using go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.5 ... avoids the panic. We have pinned controller-tools v0.16.5 in the project's go.mod but it makes difference if the go run command has the version or not. When running go run -x, I noticed that gotypesalias=0 is set when specifying @v0.16.5, whereas without it, no flag is set, and compiler enables Alias types by default, presumably because project's language level in go.mod got set to Go 1.23 as a side effect after bumping some dependencies.
A panic occurs when an embedded/inline field is a type alias and Alias types are enabled in Go.
To reproduce on the
mainbranch:The output will be following
When running
GODEBUG=gotypesalias=0 go generateor justgo generatethere will not be panic. I assume this is because of Go language level ingo.mod.FYI: Interestingly, I found the issue while running
controller-genin another project usinggo run sigs.k8s.io/controller-tools/cmd/controller-gen ...with go1.23.x. However, usinggo run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.5 ...avoids the panic. We have pinnedcontroller-toolsv0.16.5 in the project'sgo.modbut it makes difference if thego runcommand has the version or not. When runninggo run -x, I noticed thatgotypesalias=0is set when specifying@v0.16.5, whereas without it, no flag is set, and compiler enables Alias types by default, presumably because project's language level ingo.modgot set to Go 1.23 as a side effect after bumping some dependencies.