Billionmail/BillionMail · error
error reading CSV file: %v
Error message
error reading CSV file: %v
What it means
parseCSVFile reads all records with encoding/csv's reader.ReadAll() after enabling TrimLeadingSpace, LazyQuotes, and ReuseRecord. If the CSV tokenizer hits a structural problem — e.g. a bare quote mid-field, a quote not followed by a delimiter/newline, or an extraneous or missing quote — ReadAll returns a csv.ParseError and it is wrapped with this message. The wrapper discards the underlying error's line context in the string, though the %v verb keeps the wrapped text.
Source
Thrown at core/internal/controller/contact/contact.go:101
//fmt.Printf("parseTXTFile - Total valid contacts: %d\n", len(contacts))
return contacts, nil
}
// parseCSVFile parses CSV file content
func parseCSVFile(fileContent []byte) ([]*entity.Contact, error) {
// handle possible BOM
fileContent = bytes.TrimPrefix(fileContent, []byte("\xef\xbb\xbf"))
reader := csv.NewReader(bytes.NewReader(fileContent))
reader.FieldsPerRecord = -1 // Allow different number of fields per line
reader.TrimLeadingSpace = true
reader.LazyQuotes = true // Allow non-strict quotes
reader.ReuseRecord = true // Reuse record to improve performance
records, err := reader.ReadAll()
if err != nil {
return nil, fmt.Errorf("error reading CSV file: %v", err)
}
var contacts []*entity.Contact
var hasHeader bool
// Check if header exists
if len(records) > 0 {
firstRow := records[0]
if len(firstRow) >= 1 && strings.ToLower(firstRow[0]) == "email" {
hasHeader = true
}
}
// Process records
startIndex := 0
if hasHeader {
startIndex = 1
}View on GitHub (pinned to fc36c76c05)
Solutions
- Open the CSV and fix the malformed quoting on the reported line; the wrapped error text (kept via %v) includes the line/column.
- Re-export the file from the source tool with proper quoting (quote all fields).
- Consider wrapping with %w instead of %v so callers can errors.As(csv.ParseError) and report an exact row to the user.
- If files use a different delimiter, set reader.Comma before ReadAll; non-comma delimiters can cause quote-parse errors.
- If the file may be huge, switch from ReadAll to reader.Read() streaming to avoid memory pressure (does not fix parse errors but avoids OOM-path failures).
Example fix
// before
records, err := reader.ReadAll()
if err != nil {
return nil, fmt.Errorf("error reading CSV file: %v", err)
}
// after
records, err := reader.ReadAll()
if err != nil {
var perr *csv.ParseError
if errors.As(err, &perr) {
return nil, fmt.Errorf("error reading CSV file at line %d, column %d: %w", perr.Line, perr.Column, err)
}
return nil, fmt.Errorf("error reading CSV file: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// cheap pre-checks before parsing:
if len(fileContent) == 0 { return errors.New("empty CSV file") }
sniff := string(fileContent[:min(1024, len(fileContent))])
// reject obvious binary content uploaded as CSV
if strings.ContainsRune(sniff, 0) { return errors.New("file is not valid CSV text") } Try / catch
records, err := parseCSVFile(data)
if err != nil {
var perr *csv.ParseError
if errors.As(err, &perr) {
return fmt.Errorf("invalid CSV at line %d, column %d — fix quoting and re-upload", perr.Line, perr.Column)
}
return fmt.Errorf("CSV import failed: %w", err)
} Prevention
- Quote all CSV fields on export from Excel/Google Sheets
- Replace smart quotes (U+201C/U+201D) with ASCII quotes before import
- Keep LazyQuotes enabled and consider setting reader.Comma explicitly
- Surface csv.ParseError line/column to end users instead of a generic message
When it happens
Trigger: Uploading a contacts CSV where a field contains an unescaped quote (LazyQuotes only forgives some cases), a quote character is not immediately followed by a comma/newline, or the file mixes line endings with stray quotes. Any ReadAll parse error on the uploaded bytes.
Common situations: CSVs exported from Excel with embedded quotes in names; user-edited CSVs with mismatched quotes; TSV or semicolon-separated files mislabeled as CSV; files pasted from email clients introducing smart quotes (U+201C/U+201D) that csv.Reader treats as invalid.
Related errors
- failed to read CSV headers: %v
- unsupported file type: %s
- required column 'email' not found
- failed to parse alert settings: %v
- Failed to parse DKIM record: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/534a6402928a006b.
Report an issue: GitHub.