{"record":{"id":"432107a1e9ae6574","repo":"nocobase/nocobase","slug":"headers-not-found-expected-headers-headers","errorCode":null,"errorMessage":"Headers not found. Expected headers: {{headers}}","messagePattern":"Headers not found\\. Expected headers: (.+?)\\}","errorType":"validation","errorClass":"ImportValidationError","httpStatus":null,"severity":"error","filePath":"packages/plugins/@nocobase/plugin-action-import/src/server/services/xlsx-importer.ts","lineNumber":652,"sourceCode":"    const columns = this.getColumnsByPermission(ctx);\n    return columns.map((col) => col.title || col.defaultTitle);\n  }\n\n  async getData(ctx?: Context) {\n    const workbook = this.options.workbook;\n    const worksheet = workbook.Sheets[workbook.SheetNames[0]];\n\n    let data = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null, blankrows: false }) as string[][];\n\n    // Release the workbook reference immediately after converting to plain data array,\n    // so the large parsed XLSX object can be garbage collected during import.\n    this.options.workbook = null;\n\n    // Find and validate header row\n    const expectedHeaders = this.getExpectedHeaders(ctx);\n    const { headerRowIndex, headers } = this.findAndValidateHeaders({ data, expectedHeaders });\n    if (headerRowIndex === -1) {\n      throw new ImportValidationError('Headers not found. Expected headers: {{headers}}', {\n        headers: expectedHeaders.join(', '),\n      });\n    }\n    data = this.alignWithHeaders({ data, expectedHeaders, headerRowIndex });\n    // Extract data rows\n    const rows = data.slice(headerRowIndex + 1);\n\n    // if no data rows, throw error\n    if (rows.length === 0) {\n      throw new ImportValidationError('No data to import');\n    }\n\n    return [headers, ...rows];\n  }\n\n  private alignWithHeaders(params: {\n    data: string[][];\n    expectedHeaders: string[];","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-action-import/src/server/services/xlsx-importer.ts#L634-L670","documentation":"ImportValidationError thrown by getData when the uploaded spreadsheet contains no header row matching the expected headers derived from the import columns. findAndValidateHeaders scans the first rows for a row containing the expected header titles; headerRowIndex === -1 means none matched, and the error lists the expected headers so users can align their file.","triggerScenarios":"Excel file columns renamed, reordered with different titles, or the user uploads an empty/other sheet; extra title rows or the template's first rows changed; columns configured with custom titles that don't appear in the file.","commonSituations":"Downloading a template, editing headers in Excel, then importing; uploading the wrong file; localized/translated column titles differing between template generation and header matching; merged/blank top rows pushing headers beyond the scan range.","solutions":["Re-download the import template and fill it in without editing header row titles.","Ensure the sheet's header row exactly contains the expected headers listed in the error message.","Remove decorative title rows/merged cells above the real header row, or start data at the template's structure.","In code, verify getExpectedHeaders(ctx) titles match the actual sheet before calling getData."],"exampleFix":"// before (Excel row 1)\n\"User Name | Email Address\"\n// after\n\"Username | Email\" // exactly matching expected headers: \"Username, Email\"","handlingStrategy":"validation","validationCode":"const expected = importer.getExpectedHeaders(ctx); // or rebuild from columns\nconst firstRows = data.slice(0, 10).map((r) => r.map((c) => String(c ?? '').trim()));\nconst matched = firstRows.some((r) => expected.every((h) => r.includes(h)));\nif (!matched) throw new Error(`Missing headers; expected: ${expected.join(', ')}`);","typeGuard":null,"tryCatchPattern":"try {\n  await importer.data();\n} catch (e) {\n  if (e.name === 'ImportValidationError' && e.message.includes('Headers not found')) {\n    console.error('Expected headers:', e.context?.headers);\n  }\n  throw e;\n}","preventionTips":["Fill the downloaded template without renaming header cells.","Remove decorative rows/merged cells above the header row.","Upload the correct sheet/file; check active sheet in Excel.","Keep column titles stable across locales for shared templates."],"tags":["import","excel","headers","validation"],"backgroundTag":"spreadsheet-header-mismatch","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}