{"id":"92fa713da25736d7","repo":"apache/kafka","slug":"must-set-retries-to-non-zero-when-using-the-idempo","errorCode":null,"errorMessage":"Must set retries to non-zero when using the idempotent producer.","messagePattern":"Must set retries to non-zero when using the idempotent producer\\.","errorType":"validation","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/producer/ProducerConfig.java","lineNumber":656,"sourceCode":"            refinedClientId = \"producer-\" + (transactionalId != null ? transactionalId : PRODUCER_CLIENT_ID_SEQUENCE.getAndIncrement());\n        }\n        configs.put(CLIENT_ID_CONFIG, refinedClientId);\n    }\n\n    private void postProcessAndValidateIdempotenceConfigs(final Map<String, Object> configs) {\n        final Map<String, Object> originalConfigs = this.originals();\n        final String acksStr = parseAcks(this.getString(ACKS_CONFIG));\n        configs.put(ACKS_CONFIG, acksStr);\n        final boolean userConfiguredIdempotence = this.originals().containsKey(ENABLE_IDEMPOTENCE_CONFIG);\n        boolean idempotenceEnabled = this.getBoolean(ENABLE_IDEMPOTENCE_CONFIG);\n        boolean shouldDisableIdempotence = false;\n\n        // For idempotence producers, values for `retries` and `acks` and `max.in.flight.requests.per.connection` need validation\n        if (idempotenceEnabled) {\n            final int retries = this.getInt(RETRIES_CONFIG);\n            if (retries == 0) {\n                if (userConfiguredIdempotence) {\n                    throw new ConfigException(\"Must set \" + RETRIES_CONFIG + \" to non-zero when using the idempotent producer.\");\n                }\n                log.info(\"Idempotence will be disabled because {} is set to 0.\", RETRIES_CONFIG);\n                shouldDisableIdempotence = true;\n            }\n\n            final short acks = Short.parseShort(acksStr);\n            if (acks != (short) -1) {\n                if (userConfiguredIdempotence) {\n                    throw new ConfigException(\"Must set \" + ACKS_CONFIG + \" to all in order to use the idempotent \" +\n                        \"producer. Otherwise we cannot guarantee idempotence.\");\n                }\n                log.info(\"Idempotence will be disabled because {} is set to {}, not set to 'all'.\", ACKS_CONFIG, acks);\n                shouldDisableIdempotence = true;\n            }\n\n            final int inFlightConnection = this.getInt(MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION);\n            if (MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION_FOR_IDEMPOTENCE < inFlightConnection) {\n                throw new ConfigException(\"To use the idempotent producer, \" + MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION +","sourceCodeStart":638,"sourceCodeEnd":674,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/producer/ProducerConfig.java#L638-L674","documentation":"Thrown by ProducerConfig.postProcessAndValidateIdempotenceConfigs when enable.idempotence=true is explicitly set by the user while retries is configured to 0. Idempotence relies on the producer retrying on UnknownProducerId / OutOfOrderSequence, so zero retries would break the per-partition sequence-number guarantee. Note: if idempotence was NOT explicitly user-set, the producer silently disables idempotence instead of throwing.","triggerScenarios":"User provides both `enable.idempotence=true` and `retries=0` in the originals (the originals map is checked via containsKey to distinguish explicit from default). Reached at ProducerConfig.java:655-656 inside postProcessAndValidateIdempotenceConfigs, which is called from postProcessParsedConfig during KafkaProducer construction.","commonSituations":"Copy-pasting a non-idempotent producer config that hard-coded retries=0 for 'fire-and-forget' semantics and then flipping enable.idempotence=true; upgrading to a Kafka client version where enable.idempotence defaults to true while an older override still pins retries=0.","solutions":["Remove the `retries=0` override, or set `retries` to a positive value such as Integer.MAX_VALUE (the modern default used together with delivery.timeout.ms).","If fire-and-forget is genuinely required, drop `enable.idempotence=true` (and any transactional.id) so the producer can run with retries=0.","Prefer governing retry behavior via delivery.timeout.ms and let retries default."],"exampleFix":"// before\nprops.put(\"enable.idempotence\", \"true\");\nprops.put(\"retries\", \"0\");\n\n// after\nprops.put(\"enable.idempotence\", \"true\");\nprops.put(\"retries\", String.valueOf(Integer.MAX_VALUE));\nprops.put(\"delivery.timeout.ms\", \"120000\");","handlingStrategy":"validation","validationCode":"// Verify retries > 0 whenever idempotence is enabled, BEFORE building the producer.\nboolean idempotenceEnabled = Boolean.TRUE.equals(cfg.get(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG));\nint retries = ((Number) cfg.getOrDefault(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE)).intValue();\nif (idempotenceEnabled && retries == 0) {\n    throw new IllegalStateException(\"retries must be > 0 when enable.idempotence=true\");\n}\n// Simplest fix: just don't set retries, or set it high.\ncfg.putIfAbsent(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE);","typeGuard":null,"tryCatchPattern":"// Thrown during KafkaProducer construction as ConfigException.\ntry {\n    producer = new KafkaProducer<>(cfg);\n} catch (ConfigException e) {\n    if (e.getMessage().contains(\"retries\")) {\n        cfg.put(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE);\n        producer = new KafkaProducer<>(cfg);\n    } else throw e;\n}","preventionTips":["With idempotence on, either leave retries at its default (>0) or set it explicitly to a large value.","Centralize producer config in one builder/helper so the idempotence/retries pairing is enforced once.","Add an assertion/CI check that idempotent producers never have retries=0."],"tags":["kafka","producer","configuration","idempotence","transactions"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}