linshenkx/prompt-optimizer · error · Error

variables.importer.errors.csvRequiredColumns

Error message

variables.importer.errors.csvRequiredColumns

What it means

After parsing the header row, the importer looks for a name column matching name/key/variable (case-insensitive) and a value column matching value/val. If either is missing, this error is thrown because the row-to-variable mapping cannot be established.

Source

Thrown at packages/ui/src/components/variable/VariableImporter.vue:260

    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) {
        // 验证变量名格式
        if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
          throw new Error(t('variables.importer.errors.invalidVariableName', { name }))
        }
        variables[name] = value
      }
    }
  }

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Rename the columns to the supported sets: name|key|variable for the name column and value|val for the value column.
  2. Strip a leading BOM before parsing: content.replace(/^\uFEFF/, '').
  3. If arbitrary headers must be supported, add them to the findIndex arrays or let users map columns in the UI.

Example fix

// before
const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, ''))
// after
const headers = lines[0].replace(/^\uFEFF/, '').split(',').map(h => h.trim().replace(/"/g, ''))
Defensive patterns

Strategy: validation

Validate before calling

const headers = firstLine.replace(/^\uFEFF/, '').split(',').map(h => h.trim().replace(/"/g, '').toLowerCase())
const ok = headers.some(h => ['name','key','variable'].includes(h)) && headers.some(h => ['value','val'].includes(h))
if (!ok) { showError('CSV needs a name/key/variable column and a value/val column'); return }

Type guard

const hasRequiredCsvColumns = (headerLine: string): boolean => {
  const hs = headerLine.replace(/^\uFEFF/, '').split(',').map(h => h.trim().replace(/"/g, '').toLowerCase())
  return hs.some(h => ['name','key','variable'].includes(h)) && hs.some(h => ['value','val'].includes(h))
}

Try / catch

try { parseCsvVariables(content) } catch (e) { if (e instanceof Error && e.message.includes('csvRequiredColumns')) { /* show expected header format to user */ } else throw e }

Prevention

When it happens

Trigger: Importing a CSV whose header is e.g. 'variable_name,variable_value', 'k,v', 'label,content', or a CSV with no header at all (first data row is treated as the header). Quoted headers are handled, but BOM-prefixed headers (\uFEFFname) are not.

Common situations: Excel/export tools emit different column names; a UTF-8 BOM from Windows editors breaks the first header match; users rename columns before importing.

Related errors


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