apache/flink · error · ValidationException

Option '%s.%s' must be a string with single character, but w

Error message

Option '%s.%s' must be a string with single character, but was: %s

What it means

Validation error from CsvCommons.validateCharacterVal(): a CSV character option ('csv.field-delimiter', 'csv.array-element-delimiter', 'csv.quote-character', 'csv.escape-character') is present but does not unescape to exactly one character. Note field-delimiter is Java-unescaped first, so '\t' is valid while '\t\n' or 'ab' is not; the message helpfully shows the raw configured value.

Source

Thrown at flink-formats/flink-csv/src/main/java/org/apache/flink/formats/csv/CsvCommons.java:92

    /**
     * Validates the option {@code option} value must be a Character.
     *
     * @param tableOptions the table options
     * @param option the config option
     * @param unescape whether to unescape the option value
     */
    private static void validateCharacterVal(
            ReadableConfig tableOptions, ConfigOption<String> option, boolean unescape) {
        if (!tableOptions.getOptional(option).isPresent()) {
            return;
        }

        final String value =
                unescape
                        ? StringEscapeUtils.unescapeJava(tableOptions.get(option))
                        : tableOptions.get(option);
        if (value.length() != 1) {
            throw new ValidationException(
                    String.format(
                            "Option '%s.%s' must be a string with single character, but was: %s",
                            IDENTIFIER, option.key(), tableOptions.get(option)));
        }
    }

    public static Set<ConfigOption<?>> optionalOptions() {
        Set<ConfigOption<?>> options = new HashSet<>();
        options.add(FIELD_DELIMITER);
        options.add(DISABLE_QUOTE_CHARACTER);
        options.add(QUOTE_CHARACTER);
        options.add(ALLOW_COMMENTS);
        options.add(IGNORE_PARSE_ERRORS);
        options.add(ARRAY_ELEMENT_DELIMITER);
        options.add(ESCAPE_CHARACTER);
        options.add(NULL_LITERAL);
        options.add(WRITE_BIGDECIMAL_IN_SCIENTIFIC_NOTATION);
        options.add(TRIM_SPACES);

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Use exactly one character per option: ';' , '|', '\t', '\\' etc.
  2. If a multi-character separator is truly needed, switch formats (e.g. a custom format or preprocess the input) — CSV cannot express it.
  3. Double-check Java escape sequences: tab is '\t' (backslash-t in the SQL string), not the word 'tab'.

Example fix

-- before
'csv.field-delimiter' = '||'

-- after
'csv.field-delimiter' = '|'
Defensive patterns

Strategy: validation

Validate before calling

// Validate before creating the table (mirrors Flink's check):
String v = options.get(key);
String unescaped = unescapeJava && v != null ? StringEscapeUtils.unescapeJava(v) : v;
if (v != null && (unescaped == null || unescaped.length() != 1)) {
    throw new ValidationException(key + " must be a single character: " + v);
}

Prevention

When it happens

Trigger: Setting 'csv.field-delimiter'='||' or ',,' (multi-char), or an escape that unescapes to multiple chars like '\\t'; also plain strings like 'tab' instead of '\t'. Triggered during format factory validation at table creation.

Common situations: Users trying multi-char delimiters (CSV spec forbids it) and expecting Flink to accept '||'; copy-paste of raw tab characters that editors expand; supplying the literal word 'semicolon' instead of ';'.

Related errors


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