{"id":"32d0abf795e14558","repo":"apache/kafka","slug":"illegal-metadatarecoverystrategy-null","errorCode":null,"errorMessage":"Illegal MetadataRecoveryStrategy: null","messagePattern":"Illegal MetadataRecoveryStrategy: null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/MetadataRecoveryStrategy.java","lineNumber":36,"sourceCode":"\nimport java.util.Locale;\n\n/**\n * Defines the strategies which clients can follow to deal with the situation when none of the known nodes is available.\n */\npublic enum MetadataRecoveryStrategy {\n    NONE(\"none\"),\n    REBOOTSTRAP(\"rebootstrap\");\n\n    public final String name;\n\n    MetadataRecoveryStrategy(String name) {\n        this.name = name;\n    }\n\n    public static MetadataRecoveryStrategy forName(String name) {\n        if (name == null) {\n            throw new IllegalArgumentException(\"Illegal MetadataRecoveryStrategy: null\");\n        }\n        try {\n            return MetadataRecoveryStrategy.valueOf(name.toUpperCase(Locale.ROOT));\n        } catch (IllegalArgumentException e) {\n            throw new IllegalArgumentException(\"Illegal MetadataRecoveryStrategy: \" + name);\n        }\n    }\n}\n","sourceCodeStart":18,"sourceCodeEnd":45,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/MetadataRecoveryStrategy.java#L18-L45","documentation":"IllegalArgumentException thrown by MetadataRecoveryStrategy.forName when the supplied strategy name is null. The enum has only two valid names ('none', 'rebootstrap'); a null name cannot be matched, so the constructor refuses it before valueOf is even attempted. It protects NetworkClient initialisation (which reads metadata.recovery.strategy) from an undefined recovery mode.","triggerScenarios":"Setting 'metadata.recovery.strategy' to null, an empty string is not null but a genuinely null config value (e.g. programmatic Map.put(key, null)), or calling forName(null) directly. Reached via ClientUtils.createNetworkClient when building the NetworkClient.","commonSituations":"Programmatically building configs with a null value, a properties file with the key present but unassigned being parsed as null, a custom config provider returning null, or test code passing null instead of the string literal 'none'.","solutions":["Set metadata.recovery.strategy to one of the documented values: 'none' (default) or 'rebootstrap'.","If building configs in code, ensure the value is non-null before passing to the client (filter out nulls).","If the value is optional in your config layer, default it to 'none' rather than letting null propagate."],"exampleFix":"// before\nprops.put(\"metadata.recovery.strategy\", null); // NPE-prone, later throws\n// after\nprops.put(\"metadata.recovery.strategy\", \"none\");","handlingStrategy":"type-guard","validationCode":"// metadata.recovery.strategy config must be \"none\" or \"rebootstrap\"\n// (case-insensitive). Pre-validate the config string:\nimport java.util.Locale;\nimport java.util.Set;\n\nstatic final Set<String> VALID = Set.of(\"none\", \"rebootstrap\");\n\nstatic String normalizeRecoveryStrategy(String raw) {\n    if (raw == null)\n        throw new IllegalArgumentException(\n            \"metadata.recovery.strategy is null; expected one of \" + VALID);\n    String norm = raw.trim().toLowerCase(Locale.ROOT);\n    if (!VALID.contains(norm))\n        throw new IllegalArgumentException(\n            \"metadata.recovery.strategy='\" + raw + \"' is not in \" + VALID);\n    return norm;\n}\n// props.put(\"metadata.recovery.strategy\", normalizeRecoveryStrategy(raw));","typeGuard":"static boolean isValidRecoveryStrategy(String raw) {\n    if (raw == null) return false;\n    String n = raw.trim().toLowerCase(Locale.ROOT);\n    return n.equals(\"none\") || n.equals(\"rebootstrap\");\n}","tryCatchPattern":"// Thrown by MetadataRecoveryStrategy.forName during client construction.\ntry {\n    admin = AdminClient.create(props);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Illegal MetadataRecoveryStrategy\")) {\n        // Strip the bad value and let the client fall back to its default\n        // (DEFAULT_METADATA_RECOVERY_STRATEGY == REBOOTSTRAP), or fail loud:\n        props.remove(\"metadata.recovery.strategy\");\n        // then decide: retry once without it, or surface to the operator.\n        throw new ConfigurationException(e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Do not invent strategy names — only \"none\" and \"rebootstrap\" exist; future values come from new Kafka releases, so validate against the enum, not a hard-coded copy.","Default the config in your application's own defaults file rather than relying on the operator to type it correctly.","If you expose this setting via an env var or secrets manager, validate it at config-load time and fail fast with a clear message.","Remember that strategy=none disables recovery entirely — a client that loses all brokers will stay broken until restarted."],"tags":["config","metadata","validation","rebootstrap"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}