{"record":{"id":"39430a79c3d5eea9","repo":"apache/beam","slug":"failed-to-matched-a-v-field-for-sql-column-v","errorCode":null,"errorMessage":"failed to matched a %v field for SQL column: %v","messagePattern":"failed to matched a (.+?) field for SQL column: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/io/databaseio/util.go","lineNumber":52,"sourceCode":"\t\tfieldName := recordType.Field(i).Name\n\t\tindexedFields[fieldName] = i\n\t\tindexedFields[strings.ToLower(fieldName)] = i //to account for various matching strategies\n\t\taTag := recordType.Field(i).Tag\n\t\tif column := aTag.Get(\"column\"); column != \"\" {\n\t\t\tindexedFields[column] = i\n\t\t}\n\t}\n\tvar mappedFieldIndex = make([]int, len(columns))\n\tfor i, column := range columns {\n\t\tfieldIndex, ok := indexedFields[column]\n\t\tif !ok {\n\t\t\tfieldIndex, ok = indexedFields[strings.ToLower(column)]\n\t\t}\n\t\tif !ok {\n\t\t\tfieldIndex, ok = indexedFields[strings.Replace(strings.ToLower(column), \"_\", \"\", strings.Count(column, \"_\"))]\n\t\t}\n\t\tif !ok {\n\t\t\treturn nil, errors.Errorf(\"failed to matched a %v field for SQL column: %v\", recordType, column)\n\t\t}\n\t\tmappedFieldIndex[i] = fieldIndex\n\t}\n\treturn mappedFieldIndex, nil\n}\n\nfunc asDereferenceSlice(aSlice []any) {\n\tfor i, value := range aSlice {\n\t\tif value == nil {\n\t\t\tcontinue\n\t\t}\n\t\taSlice[i] = reflect.ValueOf(value).Elem().Interface()\n\n\t}\n}\n\nfunc asMap(keys []string, values []any) map[string]any {\n\tvar result = make(map[string]any)","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/io/databaseio/util.go#L34-L70","documentation":"databaseio maps SQL result columns to fields of your Go record struct via reflection (mapFields in util.go). It tries three matching strategies: exact name, case-insensitive name, and case-insensitive name with underscores stripped; an optional `column:\"...\"` struct tag is also consulted. When a returned column cannot be matched to any exported field of the struct, this error is thrown so the mismatch surfaces immediately instead of silently dropping data.","triggerScenarios":"Calling databaseio.Read (or Query) with a struct type whose exported fields do not cover all columns returned by the SQL query/statement — e.g. the query selects a column the struct lacks, the column name differs beyond the snake_case/case-insensitive heuristics, or the matching field is unexported and therefore skipped.","commonSituations":"Schema drift: a teammate added a DB column (or a SELECT *) but the Go struct wasn't updated; DBAs use naming conventions like camelCase-with-hyphens or quoted mixed-case identifiers the matcher can't normalize; forgetting the `column:\"db_name\"` tag when Go naming and SQL naming diverge; using an unexported field thinking it would still map.","solutions":["Add or update the struct field so its name (or case/underscore-insensitive variant) matches the SQL column exactly","Add an explicit struct tag: `column:\"the_sql_column_name\"` on the matching field","Narrow the query to select only columns the struct actually has (avoid SELECT *)","Export the intended field — unexported fields are ignored by mapFields","Log/inspect the actual column list (e.g. via rows.Columns()) and compare to the struct fields"],"exampleFix":"// before\ntype User struct {\n    id    int    // unexported: never matched\n    Email string\n}\n// after\ntype User struct {\n    ID    int    `column:\"user_id\"`\n    Email string\n}","handlingStrategy":"validation","validationCode":"func validateColumnsMatchStruct(columns []string, t reflect.Type) error {\n    for _, c := range columns {\n        found := false\n        for i := 0; i < t.NumField(); i++ {\n            name := t.Field(i).Name\n            tag := t.Field(i).Tag.Get(\"column\")\n            norm := strings.ReplaceAll(strings.ToLower(c), \"_\", \"\")\n            if tag == c || name == c || strings.EqualFold(name, c) || strings.EqualFold(strings.ReplaceAll(name, \"_\", \"\"), norm) {\n                found = true\n                break\n            }\n        }\n        if !found {\n            return fmt.Errorf(\"no struct field for column %q\", c)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always declare explicit `column:\"...\"` tags on struct fields mapped to DB tables","Avoid SELECT *; list exact columns that match the struct","Keep DB schema and Go structs in sync; review migrations that add columns","Use exported fields only for mapped columns"],"tags":["go","reflection","sql","schema-mapping"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}