apache/kafka · error · NumberFormatException

${about}: expected an integer or string type, but got ${node

Error message

${about}: expected an integer or string type, but got ${nodeType}

What it means

Thrown by MessageUtil.jsonNodeToInt when the Jackson JsonNode reports isTextual()==true. Note the contradiction with the message text: although it says 'expected an integer or string type', the code as written rejects JSON strings on this branch (line 118), so only JSON integer numbers actually succeed; the string/hex parsing code below is unreachable in practice. This is a long-standing quirk of the generated-message JSON reader.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/protocol/MessageUtil.java:118

        }
        return value;
    }

    public static long jsonNodeToUnsignedInt(JsonNode node, String about) {
        long value = jsonNodeToLong(node, about);
        if (value < 0 || value > UNSIGNED_INT_MAX) {
            throw new RuntimeException(about + ": value " + value +
                    " does not fit in a 32-bit unsigned integer.");
        }
        return value;
    }

    public static int jsonNodeToInt(JsonNode node, String about) {
        if (node.isInt()) {
            return node.asInt();
        }
        if (node.isTextual()) {
            throw new NumberFormatException(about + ": expected an integer or " +
                "string type, but got " + node.getNodeType());
        }
        String text = node.asText();
        if (text.startsWith("0x")) {
            try {
                return Integer.parseInt(text.substring(2), 16);
            } catch (NumberFormatException e) {
                throw new NumberFormatException(about + ": failed to " +
                    "parse hexadecimal number: " + e.getMessage());
            }
        } else {
            try {
                return Integer.parseInt(text);
            } catch (NumberFormatException e) {
                throw new NumberFormatException(about + ": failed to " +
                    "parse number: " + e.getMessage());
            }
        }

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Unquote the offending numeric value in the JSON payload (make it a JSON integer literal).
  2. Locate the field via the 'about' prefix in the message — it identifies the message class + field path.
  3. If you need to keep strings in the source format, pre-process with a JSON parser and emit integer tokens before handing the document to the Kafka deserializer.
  4. Do not be misled by the error text mentioning 'string' — strings are not actually accepted here.

Example fix

// before
{"replication_factor": "3", "topic": "orders"}
// after
{"replication_factor": 3, "topic": "orders"}
Defensive patterns

Strategy: type-guard

Validate before calling

if (node == null || !node.isInt()) throw new IllegalArgumentException("int field must be a JSON integer");

Type guard

node != null && node.isInt()

Try / catch

try { int i = MessageUtil.jsonNodeToInt(node, about); }
catch (NumberFormatException e) { /* wrong JSON node type for int field; reject record */ }

Prevention

When it happens

Trigger: A JSON object passed to a generated Message.fromJson for a int32 protocol field contains a string value where an integer literal is required. For example {"acks": "1"} or {"replication_factor": "3"} (quoted). Jackson parses the quoted token as a TextNode, isInt() is false, isTextual() is true, and line 118 throws NumberFormatException carrying nodeType=STRING.

Common situations: Authors hand-writing JSON for kafka-topics --create --replica-assignment, AlterClientQuotas, or rebalance plans quote numeric fields by habit or because a YAML→JSON tool quoted everything; users paste config from documentation that renders numbers as strings; mixing up --if-not-exists numeric flags vs their JSON string variants.

Related errors


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