{"record":{"id":"48ac6b37d7303e1e","repo":"apache/beam","slug":"unsupported-collection-type-only-normal-structs-supported","errorCode":null,"errorMessage":"unsupported collection type - only normal structs supported for writing.","messagePattern":"unsupported collection type - only normal structs supported for writing\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/io/spannerio/write.go","lineNumber":55,"sourceCode":"}\n\n// UseBatchSize explicitly sets the batch size per transaction for writes.\nfunc UseBatchSize(batchSize int) WriteOptionsFn {\n\treturn func(qo *writeOptions) error {\n\t\tqo.BatchSize = batchSize\n\t\treturn nil\n\t}\n}\n\n// Write writes the elements of the given PCollection<T> to spanner. T is required\n// to be the schema type.\nfunc Write(s beam.Scope, db string, table string, col beam.PCollection, options ...WriteOptionsFn) {\n\tif db == \"\" {\n\t\tpanic(\"no database provided!\")\n\t}\n\n\tif typex.IsCoGBK(col.Type()) || typex.IsKV(col.Type()) {\n\t\tpanic(\"unsupported collection type - only normal structs supported for writing.\")\n\t}\n\n\ts = s.Scope(\"spanner.Write\")\n\n\tbeam.ParDo0(s, newWriteFn(db, table, col.Type().Type(), options...), col)\n}\n\ntype writeFn struct {\n\tspannerFn\n\tTable     string           `json:\"table\"`   // The table to write to\n\tType      beam.EncodedType `json:\"type\"`    // Type is the encoded schema type.\n\tOptions   writeOptions     `json:\"options\"` // Spanner write options\n\tmutations []*spanner.Mutation\n}\n\nfunc newWriteFn(db string, table string, t reflect.Type, options ...WriteOptionsFn) *writeFn {\n\twriteOptions := writeOptions{\n\t\tBatchSize: 1000, // default","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/io/spannerio/write.go#L37-L73","documentation":"Panic raised by spannerio.Write when the input PCollection's type is CoGBK or KV. The Spanner writer only accepts plain element collections of schema structs; KV/CoGBK-typed data means the pipeline is feeding grouped data directly to the sink instead of extracting values first.","triggerScenarios":"Passing a PCollection<K,V> (e.g. output of beam.CoGBK or beam.ParDo emitting KV) or a CoGBK result as the col argument to spannerio.Write.","commonSituations":"Piping the result of a group-by/keyed transform directly into the Spanner sink, or reading a KV-shaped source (like some text/BigQuery reads) and writing it without reshaping.","solutions":["Reshape the data into a plain struct: use beam.ParDo to map KV pairs into a struct type whose fields match the table schema.","Re-run the producing transform so it emits structs instead of KV.","Define a Go struct mirroring the Spanner table columns and emit that from your DoFns."],"exampleFix":"// before\nspannerio.Write(s, db, \"users\", kvCol)\n// after\nstructs := beam.ParDo(s, func(k string, v []byte) User { return User{Key: k, Data: string(v)} }, kvCol)\nspannerio.Write(s, db, \"users\", structs)","handlingStrategy":"type-guard","validationCode":"if typex.IsCoGBK(col.Type()) || typex.IsKV(col.Type()) {\n    return fmt.Errorf(\"spannerio.Write requires a struct-typed PCollection, got %v\", col.Type())\n}","typeGuard":"func isStructPCollection(col beam.PCollection) bool {\n    return !typex.IsCoGBK(col.Type()) && !typex.IsKV(col.Type())\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"spannerio.Write type mismatch: %v\", r)\n    }\n}()","preventionTips":["Always map keyed/KV data through a struct-emitting ParDo before writing to Spanner.","Define one canonical struct per Spanner table and use it as the pipeline's record type.","Check col.Type() during development with a log statement when wiring new sinks."],"tags":["go","apache-beam","spanner","type-mismatch"],"backgroundTag":"incompatible-source-type","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}