{"record":{"id":"dde2ea9aa03a37cf","repo":"linshenkx/prompt-optimizer","slug":"variables-importer-errors-csvrequiredcolumns","errorCode":null,"errorMessage":"variables.importer.errors.csvRequiredColumns","messagePattern":"variables\\.importer\\.errors\\.csvRequiredColumns","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/src/components/variable/VariableImporter.vue","lineNumber":260,"sourceCode":"    return parseCsvVariables(data as string)\n  } else if (format === 'txt') {\n    return parseTxtVariables(data as string)\n  }\n  throw new Error(t('variables.importer.errors.unsupportedFormat'))\n}\n\nconst parseCsvVariables = (content: string): Record<string, string> => {\n  const lines = content.trim().split('\\n')\n  if (lines.length < 2) {\n    throw new Error(t('variables.importer.errors.csvMinRows'))\n  }\n  \n  const headers = lines[0].split(',').map(h => h.trim().replace(/\"/g, ''))\n  const nameIndex = headers.findIndex(h => ['name', 'key', 'variable'].includes(h.toLowerCase()))\n  const valueIndex = headers.findIndex(h => ['value', 'val'].includes(h.toLowerCase()))\n  \n  if (nameIndex === -1 || valueIndex === -1) {\n    throw new Error(t('variables.importer.errors.csvRequiredColumns'))\n  }\n  \n  const variables: Record<string, string> = {}\n  \n  for (let i = 1; i < lines.length; i++) {\n    const cells = lines[i].split(',').map(c => c.trim().replace(/\"/g, ''))\n    if (cells.length > Math.max(nameIndex, valueIndex)) {\n      const name = cells[nameIndex]\n      const value = cells[valueIndex]\n      if (name && value !== undefined) {\n        // 验证变量名格式\n        if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n          throw new Error(t('variables.importer.errors.invalidVariableName', { name }))\n        }\n        variables[name] = value\n      }\n    }\n  }","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/ui/src/components/variable/VariableImporter.vue#L242-L278","documentation":"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.","triggerScenarios":"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.","commonSituations":"Excel/export tools emit different column names; a UTF-8 BOM from Windows editors breaks the first header match; users rename columns before importing.","solutions":["Rename the columns to the supported sets: name|key|variable for the name column and value|val for the value column.","Strip a leading BOM before parsing: content.replace(/^\\uFEFF/, '').","If arbitrary headers must be supported, add them to the findIndex arrays or let users map columns in the UI."],"exampleFix":"// before\nconst headers = lines[0].split(',').map(h => h.trim().replace(/\"/g, ''))\n// after\nconst headers = lines[0].replace(/^\\uFEFF/, '').split(',').map(h => h.trim().replace(/\"/g, ''))","handlingStrategy":"validation","validationCode":"const headers = firstLine.replace(/^\\uFEFF/, '').split(',').map(h => h.trim().replace(/\"/g, '').toLowerCase())\nconst ok = headers.some(h => ['name','key','variable'].includes(h)) && headers.some(h => ['value','val'].includes(h))\nif (!ok) { showError('CSV needs a name/key/variable column and a value/val column'); return }","typeGuard":"const hasRequiredCsvColumns = (headerLine: string): boolean => {\n  const hs = headerLine.replace(/^\\uFEFF/, '').split(',').map(h => h.trim().replace(/\"/g, '').toLowerCase())\n  return hs.some(h => ['name','key','variable'].includes(h)) && hs.some(h => ['value','val'].includes(h))\n}","tryCatchPattern":"try { parseCsvVariables(content) } catch (e) { if (e instanceof Error && e.message.includes('csvRequiredColumns')) { /* show expected header format to user */ } else throw e }","preventionTips":["Strip the UTF-8 BOM from the first line before matching headers.","Provide a downloadable CSV template with the exact expected headers.","Document supported header synonyms in the importer UI."],"tags":["csv","headers","file-import","validation"],"backgroundTag":"csv-missing-required-column","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}