{"record":{"id":"572bff87d2f0727e","repo":"Billionmail/BillionMail","slug":"failed-to-read-csv-headers-v","errorCode":null,"errorMessage":"failed to read CSV headers: %v","messagePattern":"failed to read CSV headers: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/controller/contact/contact_v1_import_contacts.go","lineNumber":108,"sourceCode":"\t\t}\n\t}\n\n\tg.Log().Debug(ctx, \"Final parsed attributes: %v\", stringAttribs)\n\treturn stringAttribs, nil\n}\n\n// parseCSVContent Parse CSV content\nfunc parseCSVContent(ctx context.Context, content string) ([]*entity.Contact, error) {\n\tvar contacts []*entity.Contact\n\treader := csv.NewReader(bytes.NewReader([]byte(content)))\n\treader.FieldsPerRecord = -1\n\treader.LazyQuotes = true\n\treader.TrimLeadingSpace = true\n\n\t// Read headers\n\theaders, err := reader.Read()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read CSV headers: %v\", err)\n\t}\n\n\t// Find the index of the required columns\n\tcolumnIndexes := make(map[string]int)\n\tfor i, header := range headers {\n\t\theader = strings.ToLower(strings.TrimSpace(header))\n\t\tcolumnIndexes[header] = i\n\t}\n\n\t// Check the required columns\n\tif _, ok := columnIndexes[\"email\"]; !ok {\n\t\treturn nil, fmt.Errorf(\"required column 'email' not found\")\n\t}\n\n\t// Process data rows\n\tfor {\n\t\trecord, err := reader.Read()\n\t\tif err == io.EOF {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/contact/contact_v1_import_contacts.go#L90-L126","documentation":"parseCSVContent wraps the error returned by encoding/csv Reader.Read() when it fails to read the first (header) record of an uploaded contacts CSV. LazyQuotes and TrimLeadingSpace are enabled, so this fires only on structural CSV problems, not sloppy quoting. The underlying cause is preserved via %v in the wrapped message.","triggerScenarios":"reader.Read() on the header line returns a non-EOF error, e.g. a field count mismatch against the first record when useFieldsPerRecord defaults (headers row has 3 columns, later rows have 5), or a bare-quote/rune-reading error that LazyQuotes did not suppress.","commonSituations":"Users export contacts from Excel/Google Sheets with ragged rows; CSVs with embedded quotes or non-UTF8 bytes; empty or truncated uploads that produce a malformed header; BOM or CRLF quirks shifting field parsing.","solutions":["Open the uploaded CSV in a spreadsheet/text editor and fix the header row: equal number of comma-separated columns on every row.","Ensure the file is valid UTF-8 without a stray BOM and uses consistent CRLF/LF line endings.","If rows legitimately have different lengths, set reader.FieldsPerRecord = -1 before Read() to disable the field-count check.","Verify the uploaded file is a real CSV, not an xlsx or HTML error page saved with .csv extension."],"exampleFix":"// before\nreader.LazyQuotes = true\nreader.TrimLeadingSpace = true\nheaders, err := reader.Read()\n// after\nreader.LazyQuotes = true\nreader.TrimLeadingSpace = true\nreader.FieldsPerRecord = -1 // tolerate ragged rows\nheaders, err := reader.Read()","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(path)\nif err != nil { return err }\nif !utf8.Valid(data) { return errors.New(\"CSV is not valid UTF-8\") }\nr := csv.NewReader(bytes.NewReader(data))\nr.FieldsPerRecord = -1\nif _, err := r.Read(); err != nil {\n\treturn fmt.Errorf(\"invalid CSV header row: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"headers, err := parseCSVContent(ctx, file)\nif err != nil {\n\tvar csvErr *csv.ParseError\n\tif errors.As(err, &csvErr) {\n\t\treturn fmt.Errorf(\"CSV malformed at line %d: %w\", csvErr.Line, err)\n\t}\n\treturn err\n}","preventionTips":["Re-exports CSVs from the same tool and verify headers/rows in a spreadsheet before upload","Save files as UTF-8 without BOM","Validate field-count consistency before importing large files","Strip non-CSV artifacts (xlsx, HTML) at upload time"],"tags":["csv","file-upload","parsing"],"backgroundTag":"csv-parse-error","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}