pinpoint-apm/pinpoint · error · IllegalArgumentException
N:N relationship between fields and tags is not allowed.
Error message
N:N relationship between fields and tags is not allowed.
What it means
AppMetricDefinitionUtil.validateCountOfTagAndField enforces the cardinality rules for Pinpoint OTLP application-defined metrics: the relation between tag groups and fields must be 1:N (one tag group, many fields) or N:1 (many tag groups, one field). If both tagGroupList and fieldNameList have more than one element, the N:N case is rejected with IllegalArgumentException because the query/legend model cannot represent it.
Source
Thrown at otlpmetric/otlpmetric-common/src/main/java/com/navercorp/pinpoint/otlp/common/web/defined/AppMetricDefinitionUtil.java:42
import java.util.stream.Collectors;
/**
* @author minwoo-jung
*/
public class AppMetricDefinitionUtil {
static public void validate(List<AppMetricDefinition> appMetricDefinitionList) {
for (AppMetricDefinition appMetricDefinition : appMetricDefinitionList) {
List<String> tagGroupList = appMetricDefinition.getTagGroupList();
List<String> fieldNameList = appMetricDefinition.getFieldNameList();
validateCountOfTagAndField(tagGroupList, fieldNameList);
}
}
static public void validateCountOfTagAndField(List<String> tagGroupList, List<String> fieldNameList) {
if (tagGroupList.size() > 1 && fieldNameList.size() > 1) {
throw new IllegalArgumentException("N:N relationship between fields and tags is not allowed.");
}
if (tagGroupList.size() != 1 && fieldNameList.size() != 1) {
throw new IllegalArgumentException("Either tagGroupList or fieldNameList must have a size of exactly one.");
}
}
static public void generateAndSetUniqueId(List<AppMetricDefinition> appMetricDefinitionList) {
Set<String> existingIds = appMetricDefinitionList.stream()
.map(AppMetricDefinition::getId)
.filter(StringUtils::hasLength)
.collect(Collectors.toSet());
appMetricDefinitionList.stream().filter(appMetricDefinition -> StringUtils.isEmpty(appMetricDefinition.getId()))
.forEach(definition -> {
String newId;
do {View on GitHub (pinned to 744c3d3075)
Solutions
- Split the definition: create one AppMetricDefinition per (tagGroup, field) pair, keeping cardinality 1:N or N:1.
- Reduce the definition to multiple tag groups with a single field, or a single tag group with multiple fields.
- Validate the definition payload client-side before calling the save/validate API.
- If the N:N case is genuinely needed, model it as separate definitions or request a schema change upstream.
Example fix
// before new AppMetricDefinition(tagGroups=["host","region"], fieldNames=["cpu","mem"], ...) // after — one definition per pair new AppMetricDefinition(tagGroups=["host"], fieldNames=["cpu","mem"], ...) new AppMetricDefinition(tagGroups=["host","region"], fieldNames=["cpu"], ...)
Defensive patterns
Strategy: validation
Validate before calling
function isValidDefinition(def) {
const tg = def.tagGroups?.length ?? 0;
const fn = def.fieldNames?.length ?? 0;
return !(tg > 1 && fn > 1) && (tg === 1 || fn === 1);
}
if (!isValidDefinition(payload)) throw new Error("Use 1:N or N:1 tag/field cardinality"); Type guard
boolean isOneToOneSide(List<String> tagGroups, List<String> fieldNames) {
return !(tagGroups.size() > 1 && fieldNames.size() > 1)
&& (tagGroups.size() == 1 || fieldNames.size() == 1);
} Try / catch
try {
appMetricDefinitionService.save(def);
} catch (IllegalArgumentException e) {
return badRequest("Metric definition cardinality invalid: " + e.getMessage());
} Prevention
- Design definitions as one tag group with many fields, or many tag groups with one field.
- Validate definitions in the UI before allowing submit.
- Keep a JSON schema for AppMetricDefinition payloads and validate on the client.
- When migrating from other APM metric models, decompose N:N mappings into multiple definitions.
When it happens
Trigger: Saving or validating an AppMetricDefinition (via the web metric-definition API) where the definition declares multiple tagGroups AND multiple fieldNames simultaneously — e.g. a metric definition JSON with tagGroup ["a","b"] and fieldName ["f1","f2"].
Common situations: 1) User builds a metric definition in the Pinpoint web UI selecting several tag groupings and several fields at once. 2) Programmatically POSTing /api/otlp metric definitions with hand-written JSON where both lists have >1 entries. 3) Importing definitions exported from a different schema version.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Either tagGroupList or fieldNameList must have a size of exa
- value
- Resource attribute `service.name` is required to save OTLP m
- Resource attribute `pinpoint.agentId` is required to save OT
- Failed to detect pinpoint profile. Please add -Dpinpoint.act
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/4aca7f9b5083e19c.
Report an issue: GitHub.