apache/pulsar · error · org.apache.pulsar.broker.admin.RestException

Label name '%s' is invalid: OpenTelemetry reserves all label

Error message

Label name '%s' is invalid: OpenTelemetry reserves all labels starting with 'otel_' or 'otel.' for internal use

What it means

OpenTelemetry reserves label/attribute names starting with "otel_" or containing the "otel." namespace for its internal use; Pulsar mirrors that reservation and rejects such metric label names with HTTP 400 via isValidMetricsName. This prevents collisions with OpenTelemetry SDK-generated labels.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java:2571

        }

        // Prometheus reserves all labels starting with "__" for internal use.
        if (labelName.startsWith("__")) {
            throw new RestException(Response.Status.BAD_REQUEST,
                    String.format("Label name '%s' is invalid: Prometheus reserves all labels starting with '__' "
                            + "for internal use", labelName));
        }

        // Pulsar reserves all labels starting with "pulsar_" or "pulsar." for internal use.
        if (labelName.endsWith("pulsar.") || labelName.endsWith("pulsar_")) {
            throw new RestException(Response.Status.BAD_REQUEST,
                    String.format("Label name '%s' is invalid: Pulsar reserves all labels starting with 'pulsar_' "
                            + "or 'pulsar.' for internal use", labelName));
        }

        // OpenTelemetry reserves all labels starting with "otel_" or "otel." for internal use.
        if (labelName.startsWith("otel.") || labelName.startsWith("otel_")) {
            throw new RestException(Response.Status.BAD_REQUEST,
                    String.format("Label name '%s' is invalid: OpenTelemetry reserves all labels starting with "
                            + "'otel_' or 'otel.' for internal use", labelName));
        }

        boolean matches = METRICS_LABEL_NAME_PATTERN.matcher(labelName).matches();
        if (!matches) {
            throw new RestException(Response.Status.BAD_REQUEST,
                String.format("Label name '%s' is invalid: must match the regex [a-zA-Z_][a-zA-Z0-9_]*", labelName));
        }

    }
}

View on GitHub (pinned to 820761864e)

Solutions

  1. Rename the label to avoid the "otel_" prefix and "otel." namespace (e.g. "telemetry_custom").
  2. Keep OTel-specific metadata in a separate attribute set rather than Pulsar metric labels.
  3. Add pre-submission checks in tooling that generate label names to reject reserved OTel prefixes.

Example fix

// before
metrics.registerLabel("otel_deployment");

// after
metrics.registerLabel("deployment_info");
Defensive patterns

Strategy: validation

Validate before calling

if (labelName.startsWith("otel_") || labelName.startsWith("otel.")) {
    throw new IllegalArgumentException("label name uses reserved OpenTelemetry namespace: " + labelName);
}

Type guard

boolean isOtelSafe(String name) {
    return name != null && !name.startsWith("otel_") && !name.startsWith("otel.");
}

Try / catch

try {
    metricsApi.registerLabel(labelName);
} catch (RestException e) {
    if (e.getResponse().getStatus() == 400 && (labelName.startsWith("otel_") || labelName.startsWith("otel."))) {
        log.error("Label '{}' collides with OpenTelemetry reserved namespace", labelName);
    }
}

Prevention

When it happens

Trigger: Registering a custom metrics label whose name starts with "otel." or "otel_" (e.g. "otel_custom") through the broker metrics API.

Common situations: Mirroring OTel attribute naming in custom broker metrics; tooling that prefixes labels with otel_ to tag them for OpenTelemetry pipelines; reusing OTel semantic-convention names as Pulsar labels.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/7a0d8b075cf830ae. Report an issue: GitHub.