VictoriaMetrics/VictoriaMetrics · error

cannot decode InstrumentationScope: %w

Error message

cannot decode InstrumentationScope: %w

What it means

After reading field 1 successfully, decodeScopeMetrics passes the InstrumentationScope bytes to dctx.decodeInstrumentationScope; if that nested decode fails the error is wrapped as 'cannot decode InstrumentationScope'. The scope message itself (its name, version, or attributes fields) is malformed or undecodable. The %w chain retains the underlying cause.

Source

Thrown at lib/protoparser/opentelemetry/pb/pb.go:504

	}
}

func (dctx *decoderContext) decodeScopeMetrics(src []byte, disableScopeMetadata bool) error {
	// See https://github.com/open-telemetry/opentelemetry-proto/blob/049d4332834935792fd4dbd392ecd31904f99ba2/opentelemetry/proto/metrics/v1/metrics.proto#L86
	//
	// message ScopeMetrics {
	//   InstrumentationScope scope = 1;
	//   repeated Metric metrics = 2;
	// }

	if !disableScopeMetadata {
		scopeData, ok, err := easyproto.GetMessageData(src, 1)
		if err != nil {
			return fmt.Errorf("cannot read InstrumentationScope: %w", err)
		}
		if ok {
			if err := dctx.decodeInstrumentationScope(scopeData); err != nil {
				return fmt.Errorf("cannot decode InstrumentationScope: %w", err)
			}
		}
	}

	dctxSnapshot := dctx.getSnapshot()

	var fc easyproto.FieldContext
	var err error
	for len(src) > 0 {
		src, err = fc.NextField(src)
		if err != nil {
			return fmt.Errorf("cannot read the next field: %w", err)
		}
		switch fc.FieldNum {
		case 2:
			data, ok := fc.MessageData()
			if !ok {
				return fmt.Errorf("cannot read Metric data")

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Read the wrapped cause of the error to identify which scope field failed to decode
  2. Upgrade or fix the sending instrumentation SDK so it emits valid InstrumentationScope messages
  3. Decode the payload with protoc --decode_raw to validate the scope submessage
  4. Temporarily drop scope attributes/metadata on the sender (or use the disableScopeMetadata path) to isolate the failing field

Example fix

// before: hand-built scope message
scopeBytes := append([]byte{0x0a}, []byte(name)...) // missing length prefix for name
// after
var b []byte
b = easyproto.MarshalString(b, 1, name)
b = easyproto.MarshalString(b, 2, version)
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate scope metadata before attaching to metrics
if scope.Name == "" && scope.Version == "" && len(scope.Attributes) == 0 {
    return errors.New("instrumentation scope is empty; skipping attach")
}
if _, err := proto.Marshal(scope); err != nil {
    return fmt.Errorf("scope not encodable: %w", err)
}

Type guard

func validScope(s *commonpb.InstrumentationScope) bool {
    return s != nil && (s.Name != "" || s.Version != "")
}

Try / catch

if err := client.Export(ctx, req); err != nil {
    if strings.Contains(err.Error(), "cannot decode InstrumentationScope") {
        root := err
        for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }
        log.Printf("bad scope metadata, root: %v — retrying without scope attrs", root)
        return exportWithoutScopeMetadata(ctx, req)
    }
    return err
}

Prevention

When it happens

Trigger: An InstrumentationScope message inside ScopeMetrics whose fields (1=name, 2=version, 3=attributes as KeyValue) have invalid encodings — bad string lengths, corrupt attribute KeyValue bytes — causing decodeInstrumentationScope to return an error.

Common situations: Instrumentation SDKs emitting scope attributes with encoding bugs; version drift between the sending SDK's proto schema and the receiver's; payloads modified by telemetry-processing middleware that rewrites scope fields incorrectly.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/e86679716ec9926d. Report an issue: GitHub.