apache/kafka · error · ConfigException

Expected value to be a 16-bit integer (short), but it was a

Error message

Expected value to be a 16-bit integer (short), but it was a value.getClass().getName()

What it means

Thrown by ConfigDef.parseType in the SHORT branch when the supplied value is neither a java.lang.Short nor a java.lang.String. Type.SHORT accepts a boxed Short (returned as-is) or a String parsed via Short.parseShort(trimmed); any other runtime type is rejected. Kafka declares only a handful of keys as Type.SHORT (for example the replication-related defaults in broker config), and because Java integer literals are int, this fires frequently when callers pass an unqualified int into a SHORT slot.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java:750

                    if (value instanceof String)
                        return trimmed;
                    else
                        throw new ConfigException(name, value, "Expected value to be a string, but it was a " + value.getClass().getName());
                case INT:
                    if (value instanceof Integer) {
                        return value;
                    } else if (value instanceof String) {
                        return Integer.parseInt(trimmed);
                    } else {
                        throw new ConfigException(name, value, "Expected value to be a 32-bit integer, but it was a " + value.getClass().getName());
                    }
                case SHORT:
                    if (value instanceof Short) {
                        return value;
                    } else if (value instanceof String) {
                        return Short.parseShort(trimmed);
                    } else {
                        throw new ConfigException(name, value, "Expected value to be a 16-bit integer (short), but it was a " + value.getClass().getName());
                    }
                case LONG:
                    if (value instanceof Integer)
                        return ((Integer) value).longValue();
                    if (value instanceof Long)
                        return value;
                    else if (value instanceof String)
                        return Long.parseLong(trimmed);
                    else
                        throw new ConfigException(name, value, "Expected value to be a 64-bit integer (long), but it was a " + value.getClass().getName());
                case DOUBLE:
                    if (value instanceof Number)
                        return ((Number) value).doubleValue();
                    else if (value instanceof String)
                        return Double.parseDouble(trimmed);
                    else
                        throw new ConfigException(name, value, "Expected value to be a double, but it was a " + value.getClass().getName());
                case LIST:

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Box the value as a Short explicitly: (short) value or Short.valueOf(...), or pass it as a String so Short.parseShort handles it.
  2. When reading config from a typed source, emit the value as a string for SHORT-declared keys.
  3. Audit which keys are actually Type.SHORT in the relevant ConfigDef (most byte-size configs are INT or LONG) and only coerce those.

Example fix

// before
Map<String,Object> cfg = new HashMap<>();
cfg.put("some.short.key", 1024); // Integer -> ConfigException (SHORT branch)

// after
Map<String,Object> cfg = new HashMap<>();
cfg.put("some.short.key", (short) 1024);  // Short
cfg.put("some.short.key", "1024");        // or String, parsed by Short.parseShort
Defensive patterns

Strategy: type-guard

Validate before calling

// A SHORT config (e.g. "transaction.timeout.ms", "fetch.min.bytes" where short) got neither Short nor numeric String.
Object v = props.get(name);
if (v != null) {
    if (v instanceof Short) { /* ok */ }
    else if (v instanceof String) {
        try { Short.parseShort(((String) v).trim()); }
        catch (NumberFormatException nfe) {
            throw new IllegalArgumentException("Config '" + name + "' (SHORT) is not a 16-bit integer: " + v, nfe);
        }
    } else if (v instanceof Integer) {
        int i = (Integer) v;
        if (i < Short.MIN_VALUE || i > Short.MAX_VALUE) {
            throw new IllegalArgumentException("Config '" + name + "' (SHORT) out of range: " + i);
        }
        props.put(name, (short) i);
    } else if (v instanceof Number) {
        props.put(name, ((Number) v).shortValue());
    } else {
        throw new IllegalArgumentException(
            "Config '" + name + "' (SHORT) must be Short or numeric String, got " + v.getClass().getName());
    }
}

Type guard

static boolean isShortConfigValue(Object v) {
    if (v == null) return true;
    if (v instanceof Short) return true;
    if (v instanceof String) {
        try { Short.parseShort(((String) v).trim()); return true; }
        catch (NumberFormatException e) { return false; }
    }
    return false; // Integer/Long are NOT accepted by ConfigDef.parseType SHORT
}

Prevention

When it happens

Trigger: Passing an Integer, Long, or non-String/non-Short object for a Type.SHORT config key such as replica.fetch.max.bytes (where applicable), message.max.bytes (INT, not SHORT - check the actual key), or any broker/client key declared with Type.SHORT; building config programmatically with int literals.

Common situations: Programmatic construction where a helper returns int/long and the value is placed in a SHORT slot; Java does not have short literals (an unqualified 1024 is an int), so cfg.put("some.short.key", 1024) boxes to Integer and fails; YAML/JSON sources decoding numbers as Integer or Long.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/2aff90fc8fd05a60.json. Report an issue: GitHub.