Skip to content

Redundant minLength: 1 emitted on enum-constrained query parameters #1488

Description

@njheavilin

Describe the bug

When a ChoiceField is used as a query parameter via @extend_schema(parameters=[...]), the generated parameter schema includes both enum and minLength: 1.
For enum-constrained string parameters where all enum values are non-empty, minLength: 1 is redundant because enum already excludes "".
This adds schema noise and can cause some client generators to treat the extra constraint as meaningful.

To Reproduce

from rest_framework import serializers
from rest_framework.views import APIView
from drf_spectacular.utils import extend_schema

class MyParameterSerializer(serializers.Serializer):
    sort = serializers.ChoiceField(
        choices=["name", "display_name"],
        required=False,
    )

class MyView(APIView):
    @extend_schema(parameters=[MyParameterSerializer])
    def get(self, request):
        ...

Generated schema:

- name: sort
  in: query
  required: false
  schema:
    type: string
    minLength: 1          # ← redundant; enum already excludes ""
    enum:
      - display_name
      - name

The minLength: 1 originates from build_parameter_type in plumbing.py ~line 412:

if not allow_blank and schema['schema'].get('type') == 'string':
    schema['schema']['minLength'] = schema['schema'].get('minLength', 1)

Expected behavior

When enum is present and all enum values are non-empty strings, minLength: 1 should be suppressed since the constraint is strictly redundant:

- name: sort
  in: query
  required: false
  schema:
    type: string
    enum:
      - display_name
      - name

Plain CharField parameters (no enum) should continue to emit minLength: 1 as they do today — this is accurate for request-only parameters.

Suggested fix

A narrow, backward-compatible change in build_parameter_type:

if not allow_blank and schema['schema'].get('type') == 'string':
    # Skip minLength when enum already constrains values and excludes empty strings
    enum_values = schema['schema'].get('enum')
    if not enum_values or '' in enum_values:
        schema['schema']['minLength'] = schema['schema'].get('minLength', 1)

This only suppresses minLength when enum exists and all enum values are non-empty strings. All other string parameter behavior is unchanged.

For additional context, the component schema path in openapi.py (~line 1006) gates minLength behind ENFORCE_NON_BLANK_FIELDS and COMPONENT_SPLIT_REQUEST, though that distinction makes sense since component schemas can describe responses where DRF doesn't enforce allow_blank.

Happy to submit a PR if this approach seems reasonable.

Versions

  • drf-spectacular 0.29.0
  • Django 5.2+ (tested on 6.0.2)
  • DRF 3.16.1
  • Python 3.13

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions