iflytek/astron-agent · error · IllegalArgumentException
Header mismatch! Expected headers: , Actual headers:
Error message
Header mismatch! Expected headers: , Actual headers:
What it means
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.
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.
Example fix
// before
List<String> expectedHeaders = fields.stream()... .collect(Collectors.toList()); // raw, case/space sensitive
// after: normalize before comparing
List<String> expectedHeaders = fields.stream()
.filter(DbTableField::getIsRequired)
.map(f -> f.getName().trim().toLowerCase())
.sorted()
.collect(Collectors.toList());
List<String> normalizedActual = actualHeaders.stream()
.map(h -> h == null ? "" : h.trim().toLowerCase())
.sorted()
.collect(Collectors.toList());
if (!expectedHeaders.equals(normalizedActual)) { throw ... } Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the template's header row before invoking EasyExcel read
List<String> expected = requiredFields.stream().map(f -> f.getName().trim().toLowerCase()).sorted().collect(Collectors.toList());
List<String> actual = readHeaderRow(file).stream().map(h -> h == null ? "" : h.trim().toLowerCase()).sorted().collect(Collectors.toList());
if (!expected.equals(actual)) {
throw new IllegalArgumentException("Template headers do not match required table fields. Download a fresh template.");
} Try / catch
try {
EasyExcel.read(file.getInputStream(), DBExcelReadListener.class / listener).sheet().doRead();
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Header mismatch!")) {
// show expected vs actual headers to the user; prompt to re-download the template
return errorResponse(e.getMessage());
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/aa49509c743ae86c.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/database/DBExcelReadListener.java:67
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
List<String> actualHeaders = new ArrayList<>(headMap.values());
expectedHeaders = tableFields.stream()
.map(DbTableField::getName)
.filter(n -> !Arrays.asList(SYSTEM_FIELDS).contains(n))
.collect(Collectors.toList());
notNullFieldsList = tableFields.stream()
.filter(f -> !Arrays.asList(SYSTEM_FIELDS).contains(f.getName()))
.filter(DbTableField::getIsRequired)
.map(DbTableField::getName)
.collect(Collectors.toList());
// Here requires consistent order: maintain consistency with your original logic
if (!CollectionUtils.isEqualCollection(expectedHeaders, actualHeaders)) {
throw new IllegalArgumentException("Header mismatch! Expected headers: " + expectedHeaders + ", Actual headers: " + actualHeaders);
} else {
expectedHeaders = actualHeaders;
}
headerValidated = true;
}
@Override
public void invoke(Map<Integer, String> row, AnalysisContext context) {
if (!headerValidated) {
throw new BusinessException(ResponseEnum.RESPONSE_FAILED, "Headers not yet validated, please check Excel file.");
}
if (accepted >= maxRows) {
return; // Exceed limit, directly ignore subsequent rows to ensure availability
}
Map<String, Object> out = new LinkedHashMap<>();
out.put("uid", uid);
View on GitHub (pinned to 5e758547a8)