{"record":{"id":"878cf2bfc477a229","repo":"elsa-workflows/elsa-core","slug":"unexpected-end-of-protobuf-payload","errorCode":null,"errorMessage":"Unexpected end of protobuf payload.","messagePattern":"Unexpected end of protobuf payload\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/HttpProtobuf/OtlpHttpProtobufParser.cs","lineNumber":680,"sourceCode":"                case ProtobufWireType.Fixed32:\n                    EnsureAvailable(4);\n                    _remaining = _remaining[4..];\n                    field = new ProtobufField(number, wireType, default, default, default);\n                    return true;\n                default:\n                    throw new InvalidDataException($\"Unsupported protobuf wire type '{wireType}'.\");\n            }\n        }\n\n        private ulong ReadVarint()\n        {\n            ulong value = 0;\n            var shift = 0;\n\n            for (var i = 0; i < 10; i++)\n            {\n                if (_remaining.IsEmpty)\n                    throw new InvalidDataException(\"Unexpected end of protobuf payload.\");\n\n                var b = _remaining[0];\n                _remaining = _remaining[1..];\n                value |= (ulong)(b & 0x7f) << shift;\n\n                if ((b & 0x80) == 0)\n                    return value;\n\n                shift += 7;\n            }\n\n            throw new InvalidDataException(\"Invalid protobuf varint.\");\n        }\n\n        private readonly void EnsureAvailable(int byteCount)\n        {\n            if (_remaining.Length < byteCount)\n                throw new InvalidDataException(\"Unexpected end of protobuf payload.\");","sourceCodeStart":662,"sourceCodeEnd":698,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/HttpProtobuf/OtlpHttpProtobufParser.cs#L662-L698","documentation":"ReadVarint decodes at most 10 continuation bytes of a base-128 varint. If the remaining buffer empties before a terminating byte (high bit clear) is found, the payload is truncated, and the parser throws InvalidDataException with this message.","triggerScenarios":"A truncated OTLP protobuf payload ends mid-varint: the request body was cut off by a proxy timeout, Content-Length mismatch, or partial write, so the last field header/length varint never completes.","commonSituations":"Reverse proxy or load balancer buffering limits cutting large exports; exporter retry after connection reset leaves partial bytes; testing with hand-crafted byte arrays that are too short.","solutions":["Ensure the full request body is sent (check Content-Length vs actual bytes, disable body-buffering limits on proxies).","Re-send the export; truncation is usually transient network/proxy behavior.","If reproducible, capture the raw body and validate it with a protobuf decoder to find where truncation starts."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if (bytes.Length < 2 || bytes[^1] != 0) // heuristic: incomplete final varint\n    logger.LogWarning(\"OTLP payload appears truncated; not sending.\");","typeGuard":null,"tryCatchPattern":"try { await SendAsync(body); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"Unexpected end\"))\n{ logger.LogWarning(ex, \"OTLP payload truncated in transit; retrying full export.\"); }","preventionTips":["Verify proxy/load balancer body limits and timeouts allow full OTLP export bodies.","Keep export batches small so a single request is less likely to be cut off."],"tags":["protobuf","opentelemetry","truncated-payload","parsing"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}