apache/cassandra · error · ConfigurationException

Token " + token + " contains non-hex digits

Error message

Token " + token + " contains non-hex digits

What it means

ByteOrderedPartitioner's token validator normalizes a hex token string (padding odd length) and then decodes it with Hex.hexToBytes; a NumberFormatException there means the string contains characters outside [0-9a-fA-F]. It is rethrown as a ConfigurationException since the token normally comes from cassandra.yaml's initial_token.

Source

Thrown at src/java/org/apache/cassandra/dht/ByteOrderedPartitioner.java:346

        }

        public String toString(Token token)
        {
            BytesToken bytesToken = (BytesToken) token;
            return Hex.bytesToHex(bytesToken.token);
        }

        public void validate(String token) throws ConfigurationException
        {
            try
            {
                if (token.length() % 2 == 1)
                    token = "0" + token;
                Hex.hexToBytes(token);
            }
            catch (NumberFormatException e)
            {
                throw new ConfigurationException("Token " + token + " contains non-hex digits");
            }
        }

        public Token fromString(String string)
        {
            if (string.length() % 2 == 1)
                string = "0" + string;
            return new BytesToken(Hex.hexToBytes(string));
        }
    };

    public Token.TokenFactory getTokenFactory()
    {
        return tokenFactory;
    }

    @Override
    public boolean accordSupported()

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Rewrite initial_token as a valid hexadecimal string (even-length, e.g. '00ffab'), matching the BOP token format.
  2. Remove the 0x prefix and strip whitespace before the value.
  3. If the token came from another partitioner, regenerate it — token formats are not interchangeable between partitioners.
  4. Or omit initial_token and let the node pick tokens randomly (if manual byte-order placement is not required).

Example fix

// before (cassandra.yaml)
initial_token: 123456789012   # decimal, rejected
// after
initial_token: 0123456789012  # valid hex, padded to even length
Defensive patterns

Strategy: validation

Validate before calling

public static boolean isValidHexToken(String token) {
    String t = token.trim();
    if (t.startsWith("0x")) t = t.substring(2);
    if (t.isEmpty() || t.length() % 2 != 0) return false;
    return t.chars().allMatch(c -> Character.digit(c, 16) != -1);
}

Type guard

boolean isHexString(String s) { return s != null && !s.isEmpty() && s.chars().allMatch(c -> Character.digit(c, 16) != -1); }

Try / catch

try {
    factory.validate(initialToken);
} catch (ConfigurationException e) {
    throw new IllegalArgumentException("initial_token must be a valid even-length hex string", e);
}

Prevention

When it happens

Trigger: Setting initial_token to a non-hex string (e.g. decimal number, '0x...' prefix, whitespace or stray characters) with ByteOrderedPartitioner; calling TokenFactory.validate(token) programmatically with a malformed string.

Common situations: Copy-pasting a token from decimal notation used by RandomPartitioner/Murmur3Partitioner into a BOP cluster; hand-editing cassandra.yaml; '0x' prefix that Hex does not accept.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/88ae104c642970d6. Report an issue: GitHub.