apache/kafka · error · ConfigException

Invalid configuration value for 'acks': {acksString}

Error message

Invalid configuration value for 'acks': {acksString}

What it means

Thrown by ProducerConfig.parseAcks when the configured value for `acks` is neither the literal string 'all' (case-insensitive) nor a valid 16-bit signed short. parseAcks trims the input, maps 'all' to '-1', and otherwise calls Short.parseShort; any non-numeric or out-of-range input raises NumberFormatException which is converted to this ConfigException. Note the message echoes only the raw string, not which config key it came from.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/producer/ProducerConfig.java:709

        // In standard Kafka transactions, the broker enforces transaction.timeout.ms and aborts any
        // transaction that isn't completed in time. With two-phase commit (2PC), an external coordinator
        // decides when to finalize, so broker-side timeouts don't apply. Disallow using both.
        boolean enable2PC = this.getBoolean(TRANSACTION_TWO_PHASE_COMMIT_ENABLE_CONFIG);
        boolean userConfiguredTransactionTimeout = originalConfigs.containsKey(TRANSACTION_TIMEOUT_CONFIG);
        if (enable2PC && userConfiguredTransactionTimeout) {
            throw new ConfigException(
                "Cannot set " + ProducerConfig.TRANSACTION_TIMEOUT_CONFIG +
                " when " + ProducerConfig.TRANSACTION_TWO_PHASE_COMMIT_ENABLE_CONFIG +
                " is set to true. Transactions will not expire with two-phase commit enabled."
            );
        }
    }

    private static String parseAcks(String acksString) {
        try {
            return acksString.trim().equalsIgnoreCase("all") ? "-1" : Short.parseShort(acksString.trim()) + "";
        } catch (NumberFormatException e) {
            throw new ConfigException("Invalid configuration value for 'acks': " + acksString);
        }
    }

    static Map<String, Object> appendSerializerToConfig(Map<String, Object> configs,
            Serializer<?> keySerializer,
            Serializer<?> valueSerializer) {
        // validate serializer configuration, if the passed serializer instance is null, the user must explicitly set a valid serializer configuration value
        Map<String, Object> newConfigs = new HashMap<>(configs);
        if (keySerializer != null)
            newConfigs.put(KEY_SERIALIZER_CLASS_CONFIG, keySerializer.getClass());
        else if (newConfigs.get(KEY_SERIALIZER_CLASS_CONFIG) == null)
            throw new ConfigException(KEY_SERIALIZER_CLASS_CONFIG, null, "must be non-null.");
        if (valueSerializer != null)
            newConfigs.put(VALUE_SERIALIZER_CLASS_CONFIG, valueSerializer.getClass());
        else if (newConfigs.get(VALUE_SERIALIZER_CLASS_CONFIG) == null)
            throw new ConfigException(VALUE_SERIALIZER_CLASS_CONFIG, null, "must be non-null.");
        return newConfigs;
    }

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Set `acks` to one of: `all`, `-1`, `0`, or `1` as a string.
  2. If the value is supplied dynamically, validate it is one of those before constructing the producer.
  3. Check environment-variable substitution and YAML/JSON serialization layers that may have coerced the value.

Example fix

// before
props.put("acks", "any");

// after
props.put("acks", "all");
Defensive patterns

Strategy: type-guard

Validate before calling

// Normalise and validate acks BEFORE handing the config to KafkaProducer.
static String normalizeAcks(Object acksRaw) {
    String s = String.valueOf(acksRaw).trim();
    if (s.equalsIgnoreCase("all")) return "all";
    try {
        short v = Short.parseShort(s);
        if (v < -1) throw new IllegalArgumentException("acks too small: " + s);
        return Short.toString(v);
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException("Invalid acks value: " + acksRaw);
    }
}
// Caller:
cfg.put(ProducerConfig.ACKS_CONFIG, normalizeAcks(cfg.get(ProducerConfig.ACKS_CONFIG)));

Type guard

// Narrow an arbitrary config value to a proven-valid acks string.
static final java.util.regex.Pattern ACKS = java.util.regex.Pattern.compile("^(all|-1|\\d+)$", java.util.regex.Pattern.CASE_INSENSITIVE);
static boolean isAcksValue(Object o) {
    if (o == null) return false;
    String s = String.valueOf(o).trim();
    if (!ACKS.matcher(s).matches()) return false;
    try { Short.parseShort(s.equalsIgnoreCase("all") ? "-1" : s); return true; }
    catch (NumberFormatException e) { return false; }
}
// Use: assert isAcksValue(cfg.get(ProducerConfig.ACKS_CONFIG));

Try / catch

try {
    producer = new KafkaProducer<>(cfg);
} catch (ConfigException e) {
    if (e.getMessage().contains("'acks'")) {
        cfg.put(ProducerConfig.ACKS_CONFIG, "all"); // safe default
        producer = new KafkaProducer<>(cfg);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling `props.put("acks", "any")`, `acks=-30000` (out of short range), `acks=true`, or any non-numeric token other than 'all'. Triggered during KafkaProducer construction via postProcessAndValidateIdotenceConfigs -> parseAcks at ProducerConfig.java:707.

Common situations: Misspelling 'all' as 'ALL' is fine (case-insensitive) but 'any', 'yes', 'full', or 'true' are common typos; loading acks from an environment variable or YAML where it was serialized as a non-string type; passing a Boolean instead of a String.

Related errors


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