{"record":{"id":"51ed18722c62f83d","repo":"iflytek/astron-agent","slug":"response-failed-headers-not-yet-validated-please-check-excel","errorCode":"RESPONSE_FAILED","errorMessage":"Headers not yet validated, please check Excel file.","messagePattern":"Headers not yet validated, please check Excel file\\.","errorType":"validation","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/database/DBExcelReadListener.java","lineNumber":77,"sourceCode":"        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\n        for (int i = 0; i < expectedHeaders.size(); i++) {\n            String header = expectedHeaders.get(i);\n            String raw = row.get(i); // Cell raw value (may be null)\n            DbTableField meta = tableFields.stream()\n                    .filter(f -> f.getName().equals(header))\n                    .findFirst()\n                    .orElseThrow(() -> new BusinessException(ResponseEnum.RESPONSE_FAILED, \"Field \" + header + \" does not exist!\"));\n\n            Object v;\n            if (StringUtils.isBlank(raw)) {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/database/DBExcelReadListener.java#L59-L95","documentation":"This error is thrown by the EasyExcel row listener DBExcelReadListener when a data row arrives through invoke() before invokeHeadMap() has successfully validated the sheet header. The listener sets headerValidated=true only after the header collection check passes, so this indicates the header callback never ran or never completed before rows were processed. It is an internal ordering invariant: headers must be validated before any row parsing.","triggerScenarios":"Uploading an Excel file whose first sheet row is missing or empty so invokeHeadMap is not invoked before data rows; calling EasyExcel read with headRowNumber(0) or a custom read configuration that skips the header row; programmatically feeding rows to the listener without a header row.","commonSituations":"A user template file where the header row was deleted or the sheet starts at a different row; uploading a CSV-like file with no header; automated tests or scripts that construct workbooks without the header row.","solutions":["Ensure the Excel file has a header row exactly matching the expected field names as its first row and read it with the default headRowNumber (do not set headRowNumber(0)).","Download the provided import template and fill data starting from row 2.","If reading programmatically, call the listener through EasyExcel.read so invokeHeadMap is triggered, and verify headers match the table field names (order-insensitive collection equality)."],"exampleFix":"// before\nEasyExcel.read(file).headRowNumber(0).sheet().doRead(); // header skipped, rows hit invoke first\n// after\nEasyExcel.read(file).sheet().doRead(); // default headRowNumber=1, invokeHeadMap validates first","handlingStrategy":"validation","validationCode":"// before reading, check the file's first row contains the expected headers\ntry (var wb = org.apache.poi.ss.usermodel.WorkbookFactory.create(inputStream)) {\n    var row = wb.getSheetAt(0).getRow(0);\n    if (row == null || row.getLastCellNum() < 1) {\n        throw new IllegalArgumentException(\"Excel file is missing its header row\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    EasyExcel.read(file, listener).sheet().doRead();\n} catch (BusinessException e) {\n    // prompt user: re-add header row / use the official template\n}","preventionTips":["Always start from the downloaded import template; never delete the header row.","Do not configure headRowNumber(0) or skip-header options when reading.","Verify the first row of every sheet before import in the upload UI."],"tags":["excel","easyexcel","header-validation","java"],"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"}