Skip to content

Embedded / inline type aliases trigger panic #1088

@tsaarni

Description

@tsaarni

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:

  1. 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"`
 }
  1. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions