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

  1. Change the read element type to a struct whose exported fields match the query's columns.
  2. Alternatively implement the databaseio.MapLoader interface on your type so it can load values itself.
  3. 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

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


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)