Skip to content

[Runtime] Avoid nil metrics panic when backend tracing is enabled without metrics #734

Description

@cssbruno

Priority

High — generated runtime reliability when observability is partially configured.

Context

runtime/app/backend.go wraps backend handlers in traceBackendRoute. The wrapper checks for either route metrics or a tracer in the request context:

metrics := metricsFromContext(request.Context())
_, hasTracer := gowdktrace.TracerFromContext(request.Context())
if metrics == nil && !hasTracer {
    return handler(writer, request)
}

But after that branch, it unconditionally uses metrics:

routeMetric, routeStart := metrics.startRoute(kind, routePath, endpointID)
defer func() { metrics.finishRoute(routeMetric, routeStart, traceRecorder.status) }()

If a request has a tracer but no metrics object, the initial guard allows execution to continue and then dereferences metrics == nil.

Problem

Backend route tracing can panic when tracing is configured without metrics.

Consequences:

  1. Observability setup becomes all-or-nothing even though the code appears to support tracer-only operation.
  2. Generated API/action/query routes can fail before user handler logic runs.
  3. Partial instrumentation tests may miss this if they always install both metrics and tracer.
  4. The panic path can obscure the original request behavior and produce a 500 response.

Proposed direction

Handle metrics and tracing independently.

Suggested shape:

var routeMetric *routeMetricState
var routeStart time.Time
if metrics != nil {
    routeMetric, routeStart = metrics.startRoute(kind, routePath, endpointID)
    defer func() { metrics.finishRoute(routeMetric, routeStart, traceRecorder.status) }()
}

if hasTracer {
    // start span
}

Do not require metrics to record spans, and do not require a tracer to collect metrics.

Acceptance criteria

  • A request with tracer-only context does not panic.
  • A request with metrics-only context still records route metrics.
  • A request with both metrics and tracer records both.
  • A request with neither bypasses the wrapper overhead as before.
  • Tests cover action/API/query backend routes for all four combinations.
  • Panic-boundary and trace status behavior remain unchanged for actual handler panics.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions