{"record":{"id":"aa49509c743ae86c","repo":"iflytek/astron-agent","slug":"header-mismatch-expected-headers-actual-headers","errorCode":null,"errorMessage":"Header mismatch! Expected headers: , Actual headers: ","messagePattern":"Header mismatch! Expected headers: , Actual headers: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/database/DBExcelReadListener.java","lineNumber":67,"sourceCode":"\n    @Override\n    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {\n        List<String> actualHeaders = new ArrayList<>(headMap.values());\n\n        expectedHeaders = tableFields.stream()\n                .map(DbTableField::getName)\n                .filter(n -> !Arrays.asList(SYSTEM_FIELDS).contains(n))\n                .collect(Collectors.toList());\n\n        notNullFieldsList = tableFields.stream()\n                .filter(f -> !Arrays.asList(SYSTEM_FIELDS).contains(f.getName()))\n                .filter(DbTableField::getIsRequired)\n                .map(DbTableField::getName)\n                .collect(Collectors.toList());\n\n        // Here requires consistent order: maintain consistency with your original logic\n        if (!CollectionUtils.isEqualCollection(expectedHeaders, actualHeaders)) {\n            throw new IllegalArgumentException(\"Header mismatch! Expected headers: \" + expectedHeaders + \", Actual headers: \" + actualHeaders);\n        } else {\n            expectedHeaders = actualHeaders;\n        }\n        headerValidated = true;\n    }\n\n    @Override\n    public void invoke(Map<Integer, String> row, AnalysisContext context) {\n        if (!headerValidated) {\n            throw new BusinessException(ResponseEnum.RESPONSE_FAILED, \"Headers not yet validated, please check Excel file.\");\n        }\n        if (accepted >= maxRows) {\n            return; // Exceed limit, directly ignore subsequent rows to ensure availability\n        }\n\n        Map<String, Object> out = new LinkedHashMap<>();\n        out.put(\"uid\", uid);\n","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/database/DBExcelReadListener.java#L49-L85","documentation":"DBExcelReadListener.invokeHeadMap (an EasyExcel listener callback) compares the Excel header row against the required fields of the target DB table (DbTableField entries with isRequired=true). If the collection of expected headers is not an equal collection (same elements, any order) to the actual headers, it throws IllegalArgumentException 'Header mismatch! Expected headers: [...], Actual headers: [...]'. The imported spreadsheet's columns must cover exactly the table's required fields.","triggerScenarios":"Importing an Excel/CSV file whose header row does not exactly match the set of required DB table fields: a required column missing, an extra/unexpected column, renamed headers, extra whitespace/case differences, or duplicate column names changing the multiset equality.","commonSituations":"Users hand-editing exported templates (deleting or renaming columns); table schema changed (new required field) after the template was distributed; template exported from an older schema version; locale/encoding mangling header text; trailing spaces in header cells.","solutions":["Compare the Expected/Actual lists in the exception message and fix the spreadsheet so its header row exactly matches the required table fields.","Re-download/regenerate the import template from the current table schema instead of reusing an old file.","Normalize headers (trim whitespace, unify case) before comparison in invokeHeadMap to tolerate cosmetic differences.","If a new required column was added to the table, update all distributed templates and re-import.","Catch IllegalArgumentException at the import entry point and return a user-friendly message listing the mismatched headers."],"exampleFix":"// before\nList<String> expectedHeaders = fields.stream()... .collect(Collectors.toList()); // raw, case/space sensitive\n\n// after: normalize before comparing\nList<String> expectedHeaders = fields.stream()\n        .filter(DbTableField::getIsRequired)\n        .map(f -> f.getName().trim().toLowerCase())\n        .sorted()\n        .collect(Collectors.toList());\nList<String> normalizedActual = actualHeaders.stream()\n        .map(h -> h == null ? \"\" : h.trim().toLowerCase())\n        .sorted()\n        .collect(Collectors.toList());\nif (!expectedHeaders.equals(normalizedActual)) { throw ... }","handlingStrategy":"try-catch","validationCode":"// Validate the template's header row before invoking EasyExcel read\nList<String> expected = requiredFields.stream().map(f -> f.getName().trim().toLowerCase()).sorted().collect(Collectors.toList());\nList<String> actual = readHeaderRow(file).stream().map(h -> h == null ? \"\" : h.trim().toLowerCase()).sorted().collect(Collectors.toList());\nif (!expected.equals(actual)) {\n    throw new IllegalArgumentException(\"Template headers do not match required table fields. Download a fresh template.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    EasyExcel.read(file.getInputStream(), DBExcelReadListener.class / listener).sheet().doRead();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Header mismatch!\")) {\n        // show expected vs actual headers to the user; prompt to re-download the template\n        return errorResponse(e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Always import using a freshly downloaded template matching the current table schema.","Never rename, delete, or reorder header cells in the template before import.","Trim/normalize header text (case, whitespace) both when exporting templates and when comparing.","Re-distribute templates after any schema change that adds required fields."],"tags":["excel","easyexcel","validation","import","java","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}