linshenkx/prompt-optimizer · error · Error
variables.importer.errors.csvMinRows
Error message
variables.importer.errors.csvMinRows
What it means
parseCsvVariables splits the trimmed CSV content on newlines and requires at least 2 lines: one header row plus at least one data row. Fewer than 2 lines (empty file or header-only file) throws this error before any column parsing occurs.
Source
Thrown at packages/ui/src/components/variable/VariableImporter.vue:252
csv: t('variables.importer.csvTextHelp'),
txt: t('variables.importer.txtTextHelp')
}
return helps[textFormat.value] || helps.csv
}
const parseVariables = (data: unknown, format: 'csv' | 'txt' = 'csv'): Record<string, string> => {
if (format === 'csv') {
return parseCsvVariables(data as string)
} else if (format === 'txt') {
return parseTxtVariables(data as string)
}
throw new Error(t('variables.importer.errors.unsupportedFormat'))
}
const parseCsvVariables = (content: string): Record<string, string> => {
const lines = content.trim().split('\n')
if (lines.length < 2) {
throw new Error(t('variables.importer.errors.csvMinRows'))
}
const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, ''))
const nameIndex = headers.findIndex(h => ['name', 'key', 'variable'].includes(h.toLowerCase()))
const valueIndex = headers.findIndex(h => ['value', 'val'].includes(h.toLowerCase()))
if (nameIndex === -1 || valueIndex === -1) {
throw new Error(t('variables.importer.errors.csvRequiredColumns'))
}
const variables: Record<string, string> = {}
for (let i = 1; i < lines.length; i++) {
const cells = lines[i].split(',').map(c => c.trim().replace(/"/g, ''))
if (cells.length > Math.max(nameIndex, valueIndex)) {
const name = cells[nameIndex]
const value = cells[valueIndex]
if (name && value !== undefined) {View on GitHub (pinned to 3e677b1d9f)
Solutions
- Ensure the CSV has a header row (name/key/variable and value/val) plus at least one data row.
- Check the file content before import: if (content.trim().length === 0) reject early with a friendlier message.
- If CRLF/CR-only files are expected, normalize line endings: content.replace(/\r\n?/g, '\n') before splitting.
Example fix
// before
const lines = content.trim().split('\n')
// after
const lines = content.trim().replace(/\r\n?/g, '\n').split('\n').filter(l => l.trim().length > 0) Defensive patterns
Strategy: validation
Validate before calling
const text = (await file.text()).replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n').trim()
const dataRows = text.split('\n').filter(l => l.trim().length > 0)
if (dataRows.length < 2) {
showError('CSV must contain a header row and at least one data row')
return
} Type guard
const hasCsvDataRows = (content: string): boolean =>
content.trim().replace(/\r\n?/g, '\n').split('\n').filter(l => l.trim()).length >= 2 Try / catch
try { parseCsvVariables(content) } catch (e) { if (e instanceof Error && e.message.includes('csvMinRows')) { /* tell user the file is empty or header-only */ } else throw e } Prevention
- Trim and normalize line endings before parsing.
- Filter out blank lines so trailing newlines don't inflate the row count.
- Validate file size > 0 before attempting import.
When it happens
Trigger: Importing an empty CSV (content.trim() === ''), a CSV containing only a header line like 'name,value', or a file whose line endings produce a single line after trimming.
Common situations: User exports an empty template, downloads a header-only CSV, or the file read returned '' (wrong file handle, upload truncated). Files with only CR (\r) line endings also split into one 'line' since split is on '\n'.
Related errors
- variables.importer.errors.csvRequiredColumns
- variables.importer.errors.invalidVariableName
- Evaluation result is missing a valid overall score.
- variables.importer.errors.unsupportedFormat
- CONTEXT_ERROR_CODES.STORAGE_ERROR
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/e765b9643614d274.
Report an issue: GitHub.