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

  1. Ensure the CSV has a header row (name/key/variable and value/val) plus at least one data row.
  2. Check the file content before import: if (content.trim().length === 0) reject early with a friendlier message.
  3. 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

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


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/e765b9643614d274. Report an issue: GitHub.