{"id":"c754c4ec4d6ba557","repo":"apache/kafka","slug":"cannot-set-transaction-timeout-ms-when-transaction","errorCode":null,"errorMessage":"Cannot set transaction.timeout.ms when transaction.two.phase.commit.enable is set to true. Transactions will not expire with two-phase commit enabled.","messagePattern":"Cannot set transaction\\.timeout\\.ms when transaction\\.two\\.phase\\.commit\\.enable is set to true\\. Transactions will not expire with two-phase commit enabled\\.","errorType":"validation","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/producer/ProducerConfig.java","lineNumber":697,"sourceCode":"        if (shouldDisableIdempotence) {\n            configs.put(ENABLE_IDEMPOTENCE_CONFIG, false);\n            idempotenceEnabled = false;\n        }\n\n        // validate `transaction.id` after validating idempotence dependant configs because `enable.idempotence` config might be overridden\n        boolean userConfiguredTransactions = originalConfigs.containsKey(TRANSACTIONAL_ID_CONFIG);\n        if (!idempotenceEnabled && userConfiguredTransactions) {\n            throw new ConfigException(\"Cannot set a \" + ProducerConfig.TRANSACTIONAL_ID_CONFIG + \" without also enabling idempotence.\");\n        }\n\n        // Validate that transaction.timeout.ms is not set when transaction.two.phase.commit.enable is true\n        // In standard Kafka transactions, the broker enforces transaction.timeout.ms and aborts any\n        // transaction that isn't completed in time. With two-phase commit (2PC), an external coordinator\n        // decides when to finalize, so broker-side timeouts don't apply. Disallow using both.\n        boolean enable2PC = this.getBoolean(TRANSACTION_TWO_PHASE_COMMIT_ENABLE_CONFIG);\n        boolean userConfiguredTransactionTimeout = originalConfigs.containsKey(TRANSACTION_TIMEOUT_CONFIG);\n        if (enable2PC && userConfiguredTransactionTimeout) {\n            throw new ConfigException(\n                \"Cannot set \" + ProducerConfig.TRANSACTION_TIMEOUT_CONFIG +\n                \" when \" + ProducerConfig.TRANSACTION_TWO_PHASE_COMMIT_ENABLE_CONFIG +\n                \" is set to true. Transactions will not expire with two-phase commit enabled.\"\n            );\n        }\n    }\n\n    private static String parseAcks(String acksString) {\n        try {\n            return acksString.trim().equalsIgnoreCase(\"all\") ? \"-1\" : Short.parseShort(acksString.trim()) + \"\";\n        } catch (NumberFormatException e) {\n            throw new ConfigException(\"Invalid configuration value for 'acks': \" + acksString);\n        }\n    }\n\n    static Map<String, Object> appendSerializerToConfig(Map<String, Object> configs,\n            Serializer<?> keySerializer,\n            Serializer<?> valueSerializer) {","sourceCodeStart":679,"sourceCodeEnd":715,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/producer/ProducerConfig.java#L679-L715","documentation":"Thrown by ProducerConfig.postProcessAndValidateIdempotenceConfigs when transaction.two.phase.commit.enable=true is combined with an explicitly set transaction.timeout.ms. With two-phase commit (2PC), an external coordinator decides when to finalize a transaction rather than the broker's timeout, so the broker-side transaction.timeout.ms does not apply; allowing both would mislead users into thinking the broker will still abort stalled transactions. The check at ProducerConfig.java:696 fires only when both are present in originals.","triggerScenarios":"User provides both `transaction.two.phase.commit.enable=true` and `transaction.timeout.ms=<value>` in the producer config. The originals().containsKey guard means a default value alone does not trigger it — only an explicit user-set timeout does.","commonSituations":"Adopting the two-phase-commit feature while copying a full producer config template that includes transaction.timeout.ms (e.g. 60000) from a standard transactional setup; or migrating a standard EOS producer to 2PC without pruning the timeout config.","solutions":["Remove the `transaction.timeout.ms` setting from your producer config — under 2PC the external coordinator owns finalization timing.","If you genuinely need a timeout, leave 2PC disabled and use the standard transactional producer.","Audit config files, environment variables, and Spring Boot property sources for inherited transaction.timeout.ms entries."],"exampleFix":"// before\nprops.put(\"transactional.id\", \"my-tx\");\nprops.put(\"transaction.two.phase.commit.enable\", \"true\");\nprops.put(\"transaction.timeout.ms\", \"60000\");\n\n// after\nprops.put(\"transactional.id\", \"my-tx\");\nprops.put(\"transaction.two.phase.commit.enable\", \"true\");\n// transaction.timeout.ms removed; coordinator owns finalization","handlingStrategy":"validation","validationCode":"// transaction.timeout.ms is forbidden when two-phase commit is enabled.\nboolean twoPhase = Boolean.TRUE.equals(\n    cfg.get(ProducerConfig.TRANSACTION_TWO_PHASE_COMMIT_ENABLE_CONFIG));\nboolean timeoutSet = cfg.containsKey(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG);\nif (twoPhase && timeoutSet) {\n    throw new IllegalStateException(\n        \"Do not set transaction.timeout.ms when transaction.two.phase.commit.enable=true\");\n}\n// If enabling 2PC at runtime, explicitly remove any stale timeout:\nif (twoPhase) cfg.remove(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG);","typeGuard":null,"tryCatchPattern":"try {\n    producer = new KafkaProducer<>(cfg);\n} catch (ConfigException e) {\n    if (e.getMessage().contains(\"transaction.timeout.ms\")) {\n        cfg.remove(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG);\n        producer = new KafkaProducer<>(cfg);\n    } else throw e;\n}","preventionTips":["Two-phase commit moves timeout ownership to an external coordinator — never pair it with broker-side transaction.timeout.ms.","When toggling 2PC on, audit config files/env vars for leftover transaction.timeout.ms entries.","Keep 2PC and standard transactional producers as separate, named config profiles."],"tags":["kafka","producer","configuration","transactions","two-phase-commit"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}