Skip to content

Bug: Parca server panics when receiving OTLP Profile signal #5897

Description

@AntoxaBarin

Panic stacktrace:

*Parca logo*
level=info name=parca ts=2025-08-20T07:39:32.111257566Z caller=factory.go:53 msg="loading bucket configuration"
level=info name=parca ts=2025-08-20T07:39:32.114592063Z caller=badgerlogger.go:36 msg="Set nextTxnTs to 0"
level=info name=parca ts=2025-08-20T07:39:32.11654715Z caller=server.go:90 msg="starting server" addr=:7070
panic: runtime error: index out of range [2] with length 0

goroutine 245 [running]:
github.com/parca-dev/parca/pkg/normalizer.(*labelNames).addOtelAttributesFromTable(0xc00069c980, {0x0, 0x0, 0x0}, {0xc000d398b0, 0x3, 0x3})
        /home/parca/pkg/normalizer/otel.go:88 +0x13c
github.com/parca-dev/parca/pkg/normalizer.getAllLabelNames(0xc00098fa40)
        /home/parca/pkg/normalizer/otel.go:147 +0x3d9
github.com/parca-dev/parca/pkg/normalizer.OtlpRequestToArrowRecord({0x8792850, 0xc0065bf560}, 0xc00098fa40, 0xc0006c70e0, {0x87706a0, 0xb63a260})
        /home/parca/pkg/normalizer/otel.go:51 +0x1b7
github.com/parca-dev/parca/pkg/profilestore.(*ProfileColumnStore).Export(0xc000320540, {0x8792850, 0xc0065bf560}, 0xc00098fa40)
...

From OTLP proto specification (commit 3ec4649f):

message Sample {
  // locations_start_index along with locations_length refers to to a slice of locations in Profile.location_indices.
  int32 locations_start_index = 1;
  // locations_length along with locations_start_index refers to a slice of locations in Profile.location_indices.
  // Supersedes location_index.
  int32 locations_length = 2;
  // The type and unit of each value is defined by Profile.sample_type.
  repeated int64 values = 3;
  // References to attributes in ProfilesDictionary.attribute_table. [optional]
  repeated int32 attribute_indices = 4;

  // Reference to link in ProfilesDictionary.link_table. [optional]
  // It can be unset / set to 0 if no link exists, as link_table[0] is always a 'null' default value.
  int32 link_index = 5;

  // Timestamps associated with Sample represented in nanoseconds. These
  // timestamps should fall within the Profile's time range.
  repeated fixed64 timestamps_unix_nano = 6;
}

pkg/normalizer/otel.go:136-156:

func getAllLabelNames(req *otelgrpcprofilingpb.ExportProfilesServiceRequest) []string {
	allLabelNames := newLabelNames()

	for _, rp := range req.ResourceProfiles {
		allLabelNames.addOtelAttributes(rp.Resource.Attributes)

		for _, sp := range rp.ScopeProfiles {
			allLabelNames.addOtelAttributes(sp.Scope.Attributes)

			for _, p := range sp.Profiles {
				allLabelNames.addOtelAttributesFromTable(sp.Scope.Attributes, p.AttributeIndices)

				for _, sample := range p.Sample {
					allLabelNames.addOtelAttributesFromTable(sp.Scope.Attributes, sample.AttributeIndices)
                                                              ^^^^^^^^^^^^^^^^                                                                                                                          
				}
			}
		}
	}

	return allLabelNames.sorted()
}

Why do we lookup Sample's attribute in InstrumentationScope.attributes? Shouldn't we use ProfilesDictionary.attribute_table instead?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions