apache/beam · error
unsupported type
Error message
unsupported type %s
What it means
Raised by newQueryMapper when the record type passed for reading rows is neither a MapLoader implementation nor a Go struct. The read path supports only structs (mapped field-by-field) or types implementing MapLoader (self-scanning); anything else — e.g. a plain int, string, map, or interface — cannot be mapped, so the mapper creation fails eagerly before any row is read.
Solutions
- Change the read element type to a struct whose exported fields match the query's columns.
- Alternatively implement the databaseio.MapLoader interface on your type so it can load values itself.
- If you need dynamic columns, read into a struct with the needed fields instead of a map.
Example fix
// before
col := databaseio.Read[s](scope, db, "SELECT name, age FROM users") // T = string -> unsupported
// after
type User struct { Name string; Age int }
col := databaseio.Read[User](scope, db, "SELECT name, age FROM users") Defensive patterns
Strategy: type-guard
Validate before calling
// compile-time / pre-call check for the Read type parameter
func assertReadableType[T any]() error {
var zero T
t := reflect.TypeOf(&zero).Elem()
if t.Kind() == reflect.Struct { return nil }
if _, ok := any(&zero).(databaseio.MapLoader); ok { return nil }
return fmt.Errorf("type %s must be a struct or implement databaseio.MapLoader", t)
} Type guard
func isReadableType[T any]() bool {
var zero T
t := reflect.TypeOf(&zero).Elem()
return t.Kind() == reflect.Struct || func() bool { _, ok := any(&zero).(databaseio.MapLoader); return ok }()
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "unsupported type") {
return fmt.Errorf("%w; use a struct type or implement databaseio.MapLoader", err)
}
return err
} Prevention
- Always parameterize databaseio.Read with a struct type whose fields match the query columns.
- Implement databaseio.MapLoader for custom scanning behavior on non-struct types.
- Add a compile-time assertion (var _ = assertReadableType[MyType]) in package tests.
- Avoid maps, slices, or primitives as read element types — they are not supported.
When it happens
Trigger: Calling databaseio.Read with a generic type parameter (or reflection type) that is not a struct and does not implement databaseio.MapLoader — for example Read[s] with T = string, []byte, map[string]any, or a pointer-to-non-struct type.
Common situations: Developers trying to read rows into primitives or maps for convenience; passing interface types; using generics with T inferred as a non-struct type; refactoring that changed the element type from a struct to a slice or alias.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot get type arguments for
- Collection parameter is not parameterized!
- failed to map row %T
- Map type is not parameterized!
- No type parameter named
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/e47dd040d62901a0.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/io/databaseio/mapper.go:40
"reflect"
"strings"
"time"
"github.com/apache/beam/sdks/v2/go/pkg/beam/internal/errors"
)
// rowMapper represents a record mapper
type rowMapper func(value reflect.Value) ([]any, error)
// newQueryMapper creates a new record mapped
func newQueryMapper(columns []string, columnTypes []*sql.ColumnType, recordType reflect.Type) (rowMapper, error) {
val := reflect.New(recordType).Interface()
if _, isLoader := val.(MapLoader); isLoader {
return newQueryLoaderMapper(columns, columnTypes)
} else if recordType.Kind() == reflect.Struct {
return newQueryStructMapper(columns, recordType)
}
return nil, errors.Errorf("unsupported type %s", recordType)
}
// newQueryStructMapper creates a new record mapper for supplied struct type
func newQueryStructMapper(columns []string, recordType reflect.Type) (rowMapper, error) {
mappedFieldIndex, err := mapFields(columns, recordType)
if err != nil {
return nil, err
}
var record = make([]any, recordType.NumField())
var mapper = func(value reflect.Value) ([]any, error) {
value = value.Elem() //T = *T
for i, fieldIndex := range mappedFieldIndex {
record[i] = value.Field(fieldIndex).Addr().Interface()
}
return record, nil
}
return mapper, nil
}View on GitHub (pinned to 12126d8942)