prestodb/presto · error · PrestoException
SHEET_INVALID_HEADER
SHEET_INVALID_HEADER
Error message
Duplicated name %s in Column#%s and Column#%s
What it means
getColumns reads the spreadsheet's header row and lowercases each column name to build column handles. If two header cells yield the same lowercase name, a later duplicate would overwrite the earlier mapping, so the connector detects the collision and throws SHEET_INVALID_HEADER, reporting the duplicated name and the two column labels (A, B, C, ...) where it occurred.
Source
Thrown at presto-lark-sheets/src/main/java/com/facebook/presto/lark/sheets/LarkSheetsMetadata.java:295
private List<LarkSheetsColumnHandle> getColumns(LarkSheetsTableHandle table)
{
List<String> header = api.getHeaderRow(table.getSpreadsheetToken(), table.getSheetId(), table.getColumnCount());
int numColumns = header.size();
LinkedHashMap<String, LarkSheetsColumnHandle> columns = new LinkedHashMap<>(numColumns);
for (int i = 0; i < numColumns; i++) {
String rawColumnName = header.get(i);
if (rawColumnName == null) {
// Columns without name are ignored
continue;
}
String columnName = rawColumnName.toLowerCase(ENGLISH);
LarkSheetsColumnHandle column = columns.get(columnName);
if (column != null) {
String label = LarkSheetsUtil.columnIndexToColumnLabel(i);
String prevLabel = LarkSheetsUtil.columnIndexToColumnLabel(column.getIndex());
throw new PrestoException(SHEET_INVALID_HEADER,
format("Duplicated name %s in Column#%s and Column#%s", columnName, prevLabel, label));
}
columns.put(columnName, new LarkSheetsColumnHandle(columnName, VARCHAR, i));
}
return ImmutableList.copyOf(columns.values());
}
private static List<SheetInfo> filterSheets(List<SheetInfo> sheets, String filter)
{
requireNonNull(sheets, "sheets is null");
checkArgument(!isNullOrEmpty(filter), "filter is null or empty");
char firstChar = filter.charAt(0);
if (firstChar == '$') {
// filter by index
Matcher matcher = INDEX_PATTERN.matcher(filter);
if (matcher.matches()) {
int i = Integer.parseInt(filter.substring(1));View on GitHub (pinned to 55bb57d202)
Solutions
- Rename one of the duplicate header cells in the Lark sheet so all headers are unique after lowercasing.
- Trim whitespace and check case-only differences ('Name' vs 'name') in the header row.
- Restructure the sheet so each column has a distinct header name.
- If it must stay, split into two sheets and reference the one with clean headers.
Example fix
// header row before: A='Name', B='Age', C='name' // after // header row: A='Name', B='Age', C='Nickname'
Defensive patterns
Strategy: validation
Validate before calling
Set<String> seen = new HashSet<>();
for (String header : headerRow) {
String k = header.trim().toLowerCase(Locale.ROOT);
if (!seen.add(k)) throw new IllegalStateException("Duplicate header after normalization: " + k);
} Prevention
- Keep header rows unique ignoring case and whitespace
- Audit headers after collaborative edits
- Trim and normalize headers when authoring sheets
- Run a pre-query header check via DESCRIBE in CI
When it happens
Trigger: Sheet header row contains two cells whose lowercase forms are equal (e.g. 'Name' in column A and 'name' in column C, or exact duplicates), detected while building column handles for a table.
Common situations: Spreadsheet edited by multiple people who added near-duplicate headers ('Email', 'email'); trailing spaces or case differences that collapse after lowercasing; imported CSV headers with repeated fields.
Related errors
- SHEET_NAME_AMBIGUOUS
- NOT_PERMITTED
- SCHEMA_NOT_READABLE
- unexpected internal column '%s'
- KAFKA_SCHEMA_ERROR
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/5a11e7c7b1691fd1.
Report an issue: GitHub.