apache/beam · error
structx: InferFieldNames of non-struct type
Error message
structx: InferFieldNames of non-struct type %s
What it means
structx.InferFieldNames reflects over a struct type to derive field names from tags. It documents that it panics when the passed reflect.Type's Kind is not reflect.Struct. Callers such as constructSelectStatement, inferProjection, and Read rely on this precondition, so passing any non-struct type immediately aborts.
Solutions
- Dereference pointer types before calling: use t.Elem() when t.Kind() == reflect.Ptr.
- Pass the struct's value type, not a slice/map containing it (use the element type of a slice).
- Guard the call with t.Kind() != reflect.Struct before invoking InferFieldNames.
- Ensure your data model is a plain struct with exported fields when using structx-based readers.
Example fix
// before
names := structx.InferFieldNames(reflect.TypeOf(&Row{}), "beam")
// after
t := reflect.TypeOf(&Row{})
for t != nil && t.Kind() == reflect.Ptr { t = t.Elem() }
names := structx.InferFieldNames(t, "beam") Defensive patterns
Strategy: type-guard
Validate before calling
t := reflect.TypeOf(v)
for t != nil && t.Kind() == reflect.Ptr { t = t.Elem() }
if t == nil || t.Kind() != reflect.Struct {
return fmt.Errorf("structx needs a struct type, got %v", t)
} Type guard
func isStructType(t reflect.Type) bool {
for t != nil && t.Kind() == reflect.Ptr { t = t.Elem() }
return t != nil && t.Kind() == reflect.Struct
} Try / catch
defer func() {
if r := recover(); r != nil {
if s, ok := r.(string); ok && strings.Contains(s, "InferFieldNames of non-struct type") {
log.Fatalf("structx misuse: %s", s)
}
panic(r)
}
}() Prevention
- Dereference pointers with t.Elem() before calling structx helpers
- Use value types, not slices/maps, when deriving field names
- Assert struct kind in shared helpers that feed structx
- Prefer reflect.Indirect on values before passing types around
When it happens
Trigger: Passing a reflect.Type whose Kind is Slice, Map, Ptr, Int, etc. to InferFieldNames — e.g. calling it on reflect.TypeOf([]Row{}) or on a pointer type instead of the struct itself.
Common situations: Reading BigQuery rows / building projections with structx and accidentally passing reflect.TypeOf(&MyStruct{}) (pointer) or the element type of a slice; generic helpers that forward arbitrary types.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- structx: FieldIndexByTag of non-struct type
- err
- Failed to optimize MergeAccumulators for combiner
- illegal iter type
- illegal re-iter type
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/5294521a85e63af6.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/util/structx/struct.go:30
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package structx provides utilities for working with structs.
package structx
import (
"fmt"
"reflect"
"strings"
)
// InferFieldNames returns the field names of the given struct type and tag key. Includes only
// exported fields. If a field's tag key is empty or not set, uses the field's name. If a field's
// tag key is set to '-', omits the field. Panics if the type's kind is not a struct.
func InferFieldNames(t reflect.Type, key string) []string {
if t.Kind() != reflect.Struct {
panic(fmt.Sprintf("structx: InferFieldNames of non-struct type %s", t))
}
var names []string
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if field.Anonymous {
names = append(names, InferFieldNames(field.Type, key)...)
continue
}
if !field.IsExported() {
continue
}
value := field.Tag.Get(key)
name := strings.Split(value, ",")[0]View on GitHub (pinned to 12126d8942)