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
- Fix the stored definition so primaryForFieldAndTagRelation is FIELD or TAG (re-save via the web UI or update the DB row).
- Normalize enum parsing upstream: reject definitions whose relation is not FIELD/TAG at save time (validate() should set/guard it).
- If data comes from an old version, run a migration/backfill setting the field for all definitions.
- 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
- Enforce FIELD/TAG validity at definition save time, not only at query time.
- Backfill or migrate rows created before the enum was introduced.
- Use exact enum constants in API clients; beware case-sensitive string serialization.
- Log the full definition id when this throws so bad rows can be located quickly.
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
- Unknown AgentType:
- Failed to detect pinpoint profile. Please add -Dpinpoint.act
- unsupported profile or profile alias:
- UNSUPPORTED_OPERATION
- startTime not recorded
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/05d51cd37c4e20d4.
Report an issue: GitHub.