{"record":{"id":"b8a5f9536ff33739","repo":"openzipkin/zipkin","slug":"should-be-lower-hex-encoded-with-no-prefix","errorCode":null,"errorMessage":" should be lower-hex encoded with no prefix","messagePattern":" should be lower-hex encoded with no prefix","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/Span.java","lineNumber":686,"sourceCode":"    writeHexByte(data, pos + 6, (byte) ((v >>> 32L) & 0xff));\n    writeHexByte(data, pos + 8, (byte) ((v >>> 24L) & 0xff));\n    writeHexByte(data, pos + 10, (byte) ((v >>> 16L) & 0xff));\n    writeHexByte(data, pos + 12, (byte) ((v >>> 8L) & 0xff));\n    writeHexByte(data, pos + 14, (byte) (v & 0xff));\n  }\n\n  static void writeHexByte(char[] data, int pos, byte b) {\n    data[pos + 0] = HEX_DIGITS[(b >> 4) & 0xf];\n    data[pos + 1] = HEX_DIGITS[b & 0xf];\n  }\n\n  static int validateHexAndReturnZeroPrefix(String id) {\n    int zeros = 0;\n    boolean inZeroPrefix = id.charAt(0) == '0';\n    for (int i = 0, length = id.length(); i < length; i++) {\n      char c = id.charAt(i);\n      if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) {\n        throw new IllegalArgumentException(id + \" should be lower-hex encoded with no prefix\");\n      }\n      if (c != '0') {\n        inZeroPrefix = false;\n      } else if (inZeroPrefix) {\n        zeros++;\n      }\n    }\n    return zeros;\n  }\n\n  static <T extends Comparable<? super T>> List<T> sortedList(@Nullable List<T> in) {\n    if (in == null || in.isEmpty()) return Collections.emptyList();\n    if (in.size() == 1) return Collections.singletonList(in.get(0));\n    Object[] array = in.toArray();\n    Arrays.sort(array);\n\n    // dedupe\n    int j = 0, i = 1;","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/Span.java#L668-L704","documentation":"Span.validateHexAndReturnZeroPrefix(String) throws IllegalArgumentException('<id> should be lower-hex encoded with no prefix') when any character is outside [0-9a-f]. Uppercase hex (A-F), '0x' prefixes, and separators like '-' all fail — Zipkin IDs are strictly lower-hex. This helper backs id(String), parentId(String), and normalizeTraceId, so the exception surfaces from those setters.","triggerScenarios":"Calling .id(\"ABC\"), .traceId(\"0x4bf1\"), .parentId(\"4BF1F00C-E581\"), or any setter with an ID containing a non-hex character or uppercase letter.","commonSituations":"Handing UUID strings (with dashes and uppercase) straight to the builder; receiving IDs from systems that emit uppercase hex (many .NET/Go toolchains default to lowercase but custom ones don't); pasting IDs from logs with formatting artifacts.","solutions":["Normalize before setting: trim, strip any '0x' prefix, remove separators, and lowercase the value.","Map UUIDs by removing dashes and lowercasing (a 32-char UUID maps directly to a 128-bit trace ID).","Validate at ingestion with a [0-9a-f]{1,32} regex and reject/repair non-conforming IDs."],"exampleFix":"// before\nb.traceId(uuid.toString()); // \"4BF1F00C-E581-...\" uppercase + dashes\n\n// after\nb.traceId(uuid.toString().replace(\"-\", \"\").toLowerCase(Locale.ROOT));","handlingStrategy":"validation","validationCode":"static final Pattern LOWER_HEX = Pattern.compile(\"^[0-9a-f]{1,32}$\");\n\nboolean isValidZipkinId(String s) {\n  return s != null && LOWER_HEX.matcher(s).matches();\n}\n\nString sanitize(String s) {\n  return s == null ? null : s.replace(\"-\", \"\")\n      .replaceFirst(\"^0x\", \"\").toLowerCase(Locale.ROOT);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Lowercase and strip prefixes/dashes before any ID setter.","Share one regex validator for all ID fields (traceId, id, parentId)."],"tags":["zipkin","trace-id","span-id","hex","validation"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}