prestodb/presto · error · PrestoException

SHEET_BAD_DATA

SHEET_BAD_DATA

Error message

Sheet %s.%s is empty

What it means

SimpleLarkSheetsApi.getHeaderRow reads the first row of a sheet via the Lark Sheets value-range API and throws SHEET_BAD_DATA when the returned values array is empty — i.e. the sheet has no rows at all. The connector requires at least a header row to derive column names.

Source

Thrown at presto-lark-sheets/src/main/java/com/facebook/presto/lark/sheets/api/SimpleLarkSheetsApi.java:105

        }
    }

    @Override
    public List<String> getHeaderRow(String token, String sheetId, int columnCount)
    {
        String lastColumnLabel = LarkSheetsUtil.columnIndexToColumnLabel(columnCount - 1);
        String range = format("%s!A1:%s1", sheetId, lastColumnLabel);
        try {
            SheetsService.SpreadsheetsValuesGetReqCall request = sheetsService.getSpreadsheetss().valuesGet();
            request.setSpreadsheetToken(token);
            request.setRange(range);

            Response<SpreadsheetsValuesGetResult> response = request.execute();
            checkResponse(response);
            SpreadsheetsValuesGetResult data = response.getData();
            Object[] values = data.getValueRange().getValues();
            if (values.length == 0) {
                throw new PrestoException(LarkSheetsErrorCode.SHEET_BAD_DATA,
                        format("Sheet %s.%s is empty", mask(token), sheetId));
            }
            if (!(values[0] instanceof List)) {
                throw new PrestoException(LARK_API_ERROR,
                        format("Illegal response data of sheet %s @ %s", mask(token), range));
            }
            List<?> header = ((List<?>) values[0]);
            return header.stream().map(obj -> obj == null ? null : obj.toString()).collect(Collectors.toList());
        }
        catch (Exception e) {
            throw wrapApiError(e, format("Could not get data of sheet %s @ %s", mask(token), range));
        }
    }

    @Override
    public SheetValues getValues(String token, String range)
    {
        try {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Add a header row (and at least one data row) to the sheet, then retry.
  2. Verify the sheetId and range in the table/metadata definition point at the intended populated region.
  3. Catch PrestoException with code SHEET_BAD_DATA and surface a clearer message asking the user to populate the sheet.

Example fix

// before
PrestoException e = /* SHEET_BAD_DATA: Sheet <token>.<sheetId> is empty */;

// after — validate externally before querying
if (sheetIsEmpty(spreadsheet, sheetId)) {
    throw new UserGuideException("Populate sheet with a header row first");
}
Defensive patterns

Strategy: validation

Validate before calling

// before querying, verify the range has data via a metadata/preview call
boolean empty = api.getValues(token, sheetId, range) == null; // or check returned rows.isEmpty()
if (empty) throw new IllegalStateException("Sheet must contain a header row before querying");

Type guard

boolean isNonEmptySheet(SheetValues v) { return v != null && v.getRows() != null && !v.getRows().isEmpty(); }

Try / catch

try { header = api.getHeaderRow(token, sheetId, range); } catch (PrestoException e) { if (isErrorCode(e, LarkSheetsErrorCode.SHEET_BAD_DATA)) { promptUserToAddHeaderRow(); } else { throw e; } }

Prevention

When it happens

Trigger: Querying a lark-sheets table whose underlying spreadsheet range is completely empty (no header row, values array length 0 returned from getValueRange().getValues()).

Common situations: Pointing a table definition at a brand-new/blank sheet; wrong sheetId or range so the API returns an empty range; someone cleared all rows of the sheet.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/e641e067134e9eda. Report an issue: GitHub.