apache/flink · error · NumberFormatException

Invalid character.

Error message

Invalid character.

What it means

Thrown by LongParser.parseField when a byte inside the field is not an ASCII digit. The digit loop accepts only '0'..'9' after an optional leading '-'; separators, '+', '.', whitespace, or letters trigger this NumberFormatException before any overflow checking.

Source

Thrown at flink-core/src/main/java/org/apache/flink/types/parser/LongParser.java:154

        if (bytes[startPos] == delimiter) {
            throw new NumberFormatException("Empty field.");
        }

        if (bytes[startPos] == '-') {
            neg = true;
            startPos++;
            length--;
            if (length == 0 || bytes[startPos] == delimiter) {
                throw new NumberFormatException("Orphaned minus sign.");
            }
        }

        for (; length > 0; startPos++, length--) {
            if (bytes[startPos] == delimiter) {
                return neg ? -val : val;
            }
            if (bytes[startPos] < 48 || bytes[startPos] > 57) {
                throw new NumberFormatException("Invalid character.");
            }
            val *= 10;
            val += bytes[startPos] - 48;

            // check for overflow / underflow
            if (val < 0) {
                // this is an overflow/underflow, unless we hit exactly the Long.MIN_VALUE
                if (neg && val == Long.MIN_VALUE) {
                    if (length == 1 || bytes[startPos + 1] == delimiter) {
                        return Long.MIN_VALUE;
                    } else {
                        throw new NumberFormatException("value overflow");
                    }
                } else {
                    throw new NumberFormatException("value overflow");
                }
            }
        }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Emit plain digit-only integers for long columns at the producer.
  2. Parse formatted/fractional input via BigDecimal first, validate, then convert to long.
  3. Pre-scan fields for non-digit bytes and divert bad records to a dead-letter path.

Example fix

// before
long v = LongParser.parseField(bytes, start, len, '|'); // fails on "1,000,000"

// after
String field = new String(bytes, start, len, StandardCharsets.UTF_8).replace(",", "");
long v = Long.parseLong(field.trim());
Defensive patterns

Strategy: validation

Validate before calling

for (int i = 0; i < len; i++) {
    byte b = bytes[start + i];
    if (b == (byte) delimiter) break;
    if (b < 48 || b > 57) throw new IllegalArgumentException("Non-digit byte in long field: " + (char) b);
}

Try / catch

try {
    long v = LongParser.parseField(bytes, start, len, delim);
} catch (NumberFormatException e) {
    String raw = new String(bytes, start, len, StandardCharsets.UTF_8);
    long v = Long.parseLong(raw.replace(",", "").trim()); // fallback for formatted input
}

Prevention

When it happens

Trigger: Calling LongParser.parseField with fields like "1,000,000", "+9", "123 ", or "9.5" — any non-digit byte before the delimiter at LongParser.java:155.

Common situations: Grouping separators in spreadsheet/BI exports; decimal or scientific values in a long column; stray padding; schema drift changing column formats.

Understand the failure class

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/fddbc4a75259f9e8. Report an issue: GitHub.