pinpoint-apm/pinpoint · error · IllegalArgumentException

Either tagGroupList or fieldNameList must have a size of exa

Error message

Either tagGroupList or fieldNameList must have a size of exactly one.

What it means

After ruling out N:N, validateCountOfTagAndField still requires that at least one of tagGroupList or fieldNameList has exactly one element — the relation must be anchored on one side. If both lists are empty, or both sizes differ from 1 in the degenerate case (e.g. both size 0), IllegalArgumentException is thrown. (Note: an empty list combined with a list of size >1 can also reach this check since the first guard only catches the >1/>1 case.)

Source

Thrown at otlpmetric/otlpmetric-common/src/main/java/com/navercorp/pinpoint/otlp/common/web/defined/AppMetricDefinitionUtil.java:46

 */
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 {
                        newId = UUID.randomUUID().toString().substring(0, 8);
                    } while (!existingIds.add(newId));

                    definition.setId(newId);

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Ensure exactly one side is anchored: pass a single-element tagGroupList OR a single-element fieldNameList (the other side may have 1..n elements).
  2. Validate the definition before submission: require tagGroupList.size()==1 || fieldNameList.size()==1.
  3. Fix client code that builds lists conditionally so it never submits both-empty definitions.
  4. If a >1/>1 pair that passed the first guard is hitting this, split into multiple definitions as with the N:N error.

Example fix

// before
validateDefinition(tagGroups=[], fieldNames=[])  // throws
// after
if (tagGroups.size() == 1 || fieldNames.size() == 1) { save(tagGroups, fieldNames); }
else throw new IllegalArgumentException("Provide exactly one tagGroup or exactly one fieldName");
Defensive patterns

Strategy: validation

Validate before calling

if ((def.tagGroups?.length ?? 0) === 0 && (def.fieldNames?.length ?? 0) === 0) {
  throw new Error("Metric definition requires at least one tagGroup or one fieldName");
}
if (!((def.tagGroups?.length ?? 0) === 1 || (def.fieldNames?.length ?? 0) === 1)) {
  throw new Error("Exactly one side (tagGroup or fieldName) must be a single element");
}

Type guard

boolean hasAnchorSide(List<String> tagGroups, List<String> fieldNames) {
    return tagGroups.size() == 1 || fieldNames.size() == 1;
}

Try / catch

try {
    validate(def);
} catch (IllegalArgumentException e) {
    log.warn("Rejecting metric definition: {}", e.getMessage());
    return 400;
}

Prevention

When it happens

Trigger: Saving/validating an AppMetricDefinition where tagGroupList and fieldNameList are both empty, or where neither list has exactly one element (e.g. tagGroupList=[] and fieldNameList=[], or tagGroupList=[] and fieldNameList has 2+ entries).

Common situations: 1) A metric-definition POST with missing/empty `tagGroup` and `fieldName` arrays. 2) UI state where the user selected no fields and no tag grouping but submitted anyway. 3) Deserialization of JSON that dropped empty defaults leaving both lists at size 0.

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


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