{"record":{"id":"5af1b62af69a718c","repo":"pinpoint-apm/pinpoint","slug":"invalid-spanid-error","errorCode":null,"errorMessage":"invalid spanId: ${error}","messagePattern":"invalid spanId: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"otlptrace/otlptrace-collector/src/main/java/com/navercorp/pinpoint/otlp/trace/collector/mapper/OtlpIdValidator.java","lineNumber":83,"sourceCode":"     * @return the 16-byte trace ID\n     * @throws IllegalArgumentException if empty, not 16 bytes, or all-zero\n     */\n    public static byte[] validateTraceId(ByteString traceId) {\n        final String error = traceIdError(traceId);\n        if (error != null) {\n            throw new IllegalArgumentException(\"invalid traceId: \" + error);\n        }\n        return traceId.toByteArray();\n    }\n\n    /**\n     * @return the span ID as a big-endian long\n     * @throws IllegalArgumentException if empty, not 8 bytes, or all-zero\n     */\n    public static long validateSpanId(ByteString spanId) {\n        final String error = spanIdError(spanId);\n        if (error != null) {\n            throw new IllegalArgumentException(\"invalid spanId: \" + error);\n        }\n        return ByteStringUtils.parseLong(spanId);\n    }\n\n    private static String traceIdError(ByteString traceId) {\n        return idError(traceId, TRACE_ID_LEN);\n    }\n\n    private static String spanIdError(ByteString spanId) {\n        return idError(spanId, SPAN_ID_LEN);\n    }\n\n    private static String idError(ByteString id, int expectedLen) {\n        if (ByteStringUtils.isEmpty(id)) {\n            return \"empty\";\n        }\n        if (id.size() != expectedLen) {\n            return \"length \" + id.size() + \" (expected \" + expectedLen + \")\";","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/otlptrace/otlptrace-collector/src/main/java/com/navercorp/pinpoint/otlp/trace/collector/mapper/OtlpIdValidator.java#L65-L101","documentation":"OtlpIdValidator.validateSpanId validates an OTLP spanId ByteString: it must be non-empty, exactly 8 bytes, and not all zeros; on failure it throws IllegalArgumentException with the specific reason. Valid span IDs are required since they become the span's storage key.","triggerScenarios":"Exporting spans with an empty spanId, a spanId that is not 8 bytes long, or all-zero bytes (OTLP's invalid-id sentinel), typically from hand-constructed Span messages or bridged telemetry.","commonSituations":"Test fixtures using ByteString.EMPTY; bridges from systems with different span-id widths; code that sets spanId from a parsed hex string shorter than 16 hex chars; SDKs producing zeroed IDs for unsampled spans that were exported anyway.","solutions":["Generate 8 random bytes for every exported span's spanId using the official OpenTelemetry SDK.","Never export spans with empty or all-zero spanIds — filter them out before calling the collector.","When bridging IDs, pad/truncate to exactly 8 bytes and verify they are not all zero.","Catch IllegalArgumentException around span mapping and skip/log the invalid span rather than rejecting the batch."],"exampleFix":"// before\nSpan.newBuilder().setSpanId(ByteString.EMPTY)... // empty id -> throws\n// after\nbyte[] spanId = new byte[8];\nThreadLocalRandom.current().nextBytes(spanId);\nSpan.newBuilder().setSpanId(ByteString.copyFrom(spanId))...","handlingStrategy":"validation","validationCode":"boolean validSpanId(byte[] id) {\n    return id != null && id.length == 8 && !Arrays.equals(id, new byte[8]);\n}","typeGuard":"static boolean isUsableSpanId(ByteString spanId) {\n    return spanId != null\n        && spanId.size() == 8\n        && !spanId.equals(ByteString.copyFrom(new byte[8]));\n}","tryCatchPattern":"try {\n    long spanId = OtlpIdValidator.validateSpanId(span.getSpanId());\n} catch (IllegalArgumentException e) {\n    log.warn(\"skipping span with bad spanId: {}\", e.getMessage());\n    continue; // skip span, continue batch\n}","preventionTips":["Generate 8-byte random span IDs via the official SDK","Filter out empty/all-zero span IDs before export","Validate hex-string IDs are 16 hex chars before converting to bytes","Drop unsampled/placeholder spans instead of exporting them with sentinel IDs"],"tags":["java","otlp","span-id","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}