langgenius/dify · warning · ValueError

Unsupported query list type.

Error message

Unsupported query list type.

What it means

A Pydantic field_validator error on RosterListQuery.statuses/sources: the field normalizes None/empty-string to [] and accepts a list, but any other type (e.g. a bare string, number, dict) is rejected. The validator runs in mode='before', so it sees the raw query value before Pydantic's default list coercion. Surfaces as a 422 validation error.

Source

Thrown at api/controllers/console/agent/roster.py:205

    sort_order: str = Field(default="desc", description="Sort order: asc or desc")
    start: str | None = Field(default=None, description="Start date (YYYY-MM-DD HH:MM)")
    end: str | None = Field(default=None, description="End date (YYYY-MM-DD HH:MM)")

    @field_validator("keyword", "status", "source", "start", "end", mode="before")
    @classmethod
    def empty_string_to_none(cls, value: str | None) -> str | None:
        if value == "":
            return None
        return value

    @field_validator("statuses", "sources", mode="before")
    @classmethod
    def empty_list_values_to_list(cls, value: object) -> list[str]:
        if value in (None, ""):
            return []
        if isinstance(value, list):
            return [str(item).strip() for item in value if str(item).strip()]
        raise ValueError("Unsupported query list type.")

    @field_validator("sort_by")
    @classmethod
    def validate_sort_by(cls, value: str) -> str:
        normalized = value.strip().lower()
        if normalized not in {"created_at", "updated_at"}:
            raise ValueError("sort_by must be created_at or updated_at")
        return normalized

    @field_validator("sort_order")
    @classmethod
    def validate_sort_order(cls, value: str) -> str:
        normalized = value.strip().lower()
        if normalized not in {"asc", "desc"}:
            raise ValueError("sort_order must be asc or desc")
        return normalized

View on GitHub (pinned to ef8544b173)

Solutions

  1. Send list-valued query params using array encoding: ?statuses=active&statuses=ready (Flask returns a list) or ?statuses[]=active.
  2. If you only need one value, still pass it as a single-element list, or send an empty string/omit to mean 'no filter'.
  3. Update the client serializer to always emit list form for statuses and sources.
  4. Unit-test the client against the OpenAPI schema to catch scalar-vs-list regressions.

Example fix

# before
?statuses=active
# after
?statuses=active&statuses=ready   # or ?statuses[]=active
Defensive patterns

Strategy: validation

Validate before calling

from typing import Any

def coerce_to_list(value: Any) -> list[str]:
    if value in (None, ''):
        return []
    if isinstance(value, list):
        return [str(v).strip() for v in value if str(v).strip()]
    raise TypeError('statuses/sources must be a list')

Type guard

from typing import Any

def is_list_like_query_value(value: Any) -> bool:
    return value is None or value == '' or isinstance(value, list)

Prevention

When it happens

Trigger: GET /console/agents (roster list) with statuses or sources sent as a non-list scalar, e.g. ?statuses=active (no list encoding) where the client/framework did not wrap it in a list, or ?sources=workflow:abc as a bare string instead of repeated/array form.

Common situations: Client that sends a single value without array encoding (statuses=active vs statuses[]=active or statuses=active&statuses=ready); a malformed query string built by hand; a proxy that collapsed repeated params into a single scalar; version change after the validator tightened to reject scalars.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/416ff95bce5b2595. Report an issue: GitHub.