makeplane/plane · error · ValidationError

Invalid group_by field: {group_by}

Error message

Invalid group_by field: {group_by}

What it means

Django ValidationError raised by `build_analytics_chart` (build_chart.py:165) when a non-None `group_by` is not a key of `x_axis_mapper`. group_by is optional (None is allowed and skips the check), but any supplied value must be one of the 13 UPPERCASE mapper keys. Note group_by is validated against the same x_axis_mapper as x_axis, not a separate grouping map.

Source

Thrown at apps/api/plane/utils/build_chart.py:165

            "count": item["count"],
        }
        for item in data
    ]


def build_analytics_chart(
    queryset: QuerySet[Issue],
    x_axis: str,
    group_by: Optional[str] = None,
    date_filter: Optional[str] = None,
) -> Dict[str, Union[List[Dict[str, Any]], Dict[str, str]]]:
    # Validate x_axis
    if x_axis not in x_axis_mapper:
        raise ValidationError(f"Invalid x_axis field: {x_axis}")

    # Validate group_by
    if group_by and group_by not in x_axis_mapper:
        raise ValidationError(f"Invalid group_by field: {group_by}")

    field_mapping = get_x_axis_field()

    id_field, name_field, additional_filter = field_mapping.get(x_axis, (None, None, {}))
    group_field, group_name_field, group_additional_filter = field_mapping.get(group_by, (None, None, {}))

    # Apply additional filters if they exist
    if additional_filter or {}:
        queryset = queryset.filter(**additional_filter)

    if group_additional_filter or {}:
        queryset = queryset.filter(**group_additional_filter)

    aggregate_func = Count("id", distinct=True)

    if group_field:
        response, schema = build_grouped_chart_response(
            queryset,

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Pass group_by as one of the 13 UPPERCASE x_axis_mapper keys, or None to skip grouping.
  2. Normalize user-supplied group_by: `group_by = group_by.strip().upper() if group_by else None`.
  3. Assert `group_by in x_axis_mapper` before the call when group_by is set.
  4. Remember group_by and x_axis share the same valid set - there is no group-specific vocabulary.

Example fix

# before
build_analytics_chart(qs, x_axis="STATES", group_by="assignees__id")

# after
build_analytics_chart(qs, x_axis="STATES", group_by="ASSIGNEES")
Defensive patterns

Strategy: validation

Validate before calling

from plane.utils.build_chart import x_axis_mapper

def is_valid_group_by(group_by) -> bool:
    # group_by is optional and shares the same x_axis_mapper as x_axis
    return group_by is None or group_by in x_axis_mapper

Type guard

from plane.utils.build_chart import x_axis_mapper

def is_valid_group_by(value) -> bool:
    return value is None or (isinstance(value, str) and value in x_axis_mapper)

Try / catch

from django.core.exceptions import ValidationError
try:
    build_analytics_chart(qs, x_axis, group_by)
except ValidationError as e:
    if 'Invalid group_by field' in str(e):
        return bad_request(str(e))

Prevention

When it happens

Trigger: Calling build_analytics_chart with a group_by that is non-None and not in x_axis_mapper - e.g. 'assignees' (lowercase), 'ASSIGNEE' (wrong singular), or any analytics_plot lowercase field.

Common situations: Using a lowercase or singular form of a category ('label' vs 'LABELS'); forwarding user input without normalizing case; mixing analytics_plot field names into build_chart calls.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/e3cee10d41800105. Report an issue: GitHub.