pinpoint-apm/pinpoint · error · IllegalArgumentException

Unknown primaryForFieldAndTagRelation:

Error message

Unknown primaryForFieldAndTagRelation: 

What it means

getLegendName derives chart legend labels from the metric definition's primaryForFieldAndTagRelation enum, which must be FIELD or TAG (the two valid cardinality anchors). When the stored/serialized value is anything else — including null from an unset or legacy record — the default branch throws IllegalArgumentException with the offending value appended. (The trailing colon with nothing after it in some logs indicates the value's toString() was null or empty.)

Source

Thrown at otlpmetric/otlpmetric-web/src/main/java/com/navercorp/pinpoint/otlp/web/service/OtlpMetricWebServiceImpl.java:198

                }
            }

        return metricData;
    }

    private MetricData createEmptyMetricData(TimeWindow timeWindow, ChartType chartType) {
        List<Long> windows = timeWindow.getTimeseriesWindows();
        return new MetricData(windows, chartType, EMPTY_STRING, "There is no metadata for the metric query.");
    }

    private String getLegendName(OtlpMetricDataQueryParameter chartQueryParameter, PrimaryForFieldAndTagRelation primaryForFieldAndTagRelation) {
        switch (primaryForFieldAndTagRelation) {
            case FIELD:
                return chartQueryParameter.getRawTags();
            case TAG:
                return chartQueryParameter.getFieldName();
            default:
                throw new IllegalArgumentException("Unknown primaryForFieldAndTagRelation: " + primaryForFieldAndTagRelation);
        }
    }


    private void addMetricValue(TimeWindow timeWindow,
                                List<DataPoint> meticDataList, MetricData metricData, String legendName, String version){
        TimeSeriesBuilder timeSeriesBuilder = new TimeSeriesBuilder(timeWindow);
        List<DataPoint> metricPointList = timeSeriesBuilder.build(MetricPoints::createUnCollectedPoint, meticDataList);
        List<Number> valueList = metricPointList.stream().map(DataPoint::getValue).collect(Collectors.toList());

        metricData.addMetricValue(new MetricValue(legendName, valueList, version));

//                if (otlpMetricChartResults != null) {
        // TODO : (minwoo) Get summary data
        //                    if ((metricData.hasSummaryField()) && (chartFieldView != null)) {


//                        OtlpMetricDataQueryParameter chartQueryParameter = setupQueryParameter(builder, key);

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Fix the stored definition so primaryForFieldAndTagRelation is FIELD or TAG (re-save via the web UI or update the DB row).
  2. Normalize enum parsing upstream: reject definitions whose relation is not FIELD/TAG at save time (validate() should set/guard it).
  3. If data comes from an old version, run a migration/backfill setting the field for all definitions.
  4. For a tolerant read path, fall back to a default legend instead of throwing (see exampleFix).

Example fix

// before
default:
    throw new IllegalArgumentException("Unknown primaryForFieldAndTagRelation: " + primaryForFieldAndTagRelation);
// after
default:
    if (primaryForFieldAndTagRelation == null) {
        return chartQueryParameter.getRawTags(); // legacy fallback
    }
    throw new IllegalArgumentException("Unknown primaryForFieldAndTagRelation: " + primaryForFieldAndTagRelation);
Defensive patterns

Strategy: try-catch

Validate before calling

function validateRelation(def) {
  if (def.primaryForFieldAndTagRelation !== 'FIELD' && def.primaryForFieldAndTagRelation !== 'TAG') {
    throw new Error("primaryForFieldAndTagRelation must be FIELD or TAG, got: " + def.primaryForFieldAndTagRelation);
  }
}

Type guard

boolean isValidRelation(AppMetricDefinition definition) {
    return definition.getPrimaryForFieldAndTagRelation() == FieldAndTagRelation.FIELD
        || definition.getPrimaryForFieldAndTagRelation() == FieldAndTagRelation.TAG;
}

Try / catch

try {
    String legend = getLegendName(primaryForFieldAndTagRelation, chartQueryParameter);
} catch (IllegalArgumentException e) {
    log.warn("Falling back to default legend; definition relation invalid: {}", e.getMessage());
    legend = chartQueryParameter.getFieldName();
}

Prevention

When it happens

Trigger: Querying metric data (getMetricData → getLegendName) for a metric definition whose primaryForFieldAndTagRelation field is null or an unrecognized value — e.g. data written by an older Pinpoint version before the enum existed, or a manually edited DB row / API payload with a typo like "Field" (wrong case) or "fieldAndTag".

Common situations: 1) Legacy rows in the OTLP metric-definition storage predating the FIELD/TAG enum. 2) REST clients sending lowercase/mis-spelled relation values. 3) Deserialization frameworks mapping unknown strings to null. 4) Bug where the definition was saved without computing the primary relation (validateCountOfTagAndField enforces 1:N or N:1, but the primary flag may not have been set).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/05d51cd37c4e20d4. Report an issue: GitHub.