{"record":{"id":"416ff95bce5b2595","repo":"langgenius/dify","slug":"unsupported-query-list-type","errorCode":null,"errorMessage":"Unsupported query list type.","messagePattern":"Unsupported query list type\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"api/controllers/console/agent/roster.py","lineNumber":205,"sourceCode":"    sort_order: str = Field(default=\"desc\", description=\"Sort order: asc or desc\")\n    start: str | None = Field(default=None, description=\"Start date (YYYY-MM-DD HH:MM)\")\n    end: str | None = Field(default=None, description=\"End date (YYYY-MM-DD HH:MM)\")\n\n    @field_validator(\"keyword\", \"status\", \"source\", \"start\", \"end\", mode=\"before\")\n    @classmethod\n    def empty_string_to_none(cls, value: str | None) -> str | None:\n        if value == \"\":\n            return None\n        return value\n\n    @field_validator(\"statuses\", \"sources\", mode=\"before\")\n    @classmethod\n    def empty_list_values_to_list(cls, value: object) -> list[str]:\n        if value in (None, \"\"):\n            return []\n        if isinstance(value, list):\n            return [str(item).strip() for item in value if str(item).strip()]\n        raise ValueError(\"Unsupported query list type.\")\n\n    @field_validator(\"sort_by\")\n    @classmethod\n    def validate_sort_by(cls, value: str) -> str:\n        normalized = value.strip().lower()\n        if normalized not in {\"created_at\", \"updated_at\"}:\n            raise ValueError(\"sort_by must be created_at or updated_at\")\n        return normalized\n\n    @field_validator(\"sort_order\")\n    @classmethod\n    def validate_sort_order(cls, value: str) -> str:\n        normalized = value.strip().lower()\n        if normalized not in {\"asc\", \"desc\"}:\n            raise ValueError(\"sort_order must be asc or desc\")\n        return normalized\n\n","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/agent/roster.py#L187-L223","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Send list-valued query params using array encoding: ?statuses=active&statuses=ready (Flask returns a list) or ?statuses[]=active.","If you only need one value, still pass it as a single-element list, or send an empty string/omit to mean 'no filter'.","Update the client serializer to always emit list form for statuses and sources.","Unit-test the client against the OpenAPI schema to catch scalar-vs-list regressions."],"exampleFix":"# before\n?statuses=active\n# after\n?statuses=active&statuses=ready   # or ?statuses[]=active","handlingStrategy":"validation","validationCode":"from typing import Any\n\ndef coerce_to_list(value: Any) -> list[str]:\n    if value in (None, ''):\n        return []\n    if isinstance(value, list):\n        return [str(v).strip() for v in value if str(v).strip()]\n    raise TypeError('statuses/sources must be a list')","typeGuard":"from typing import Any\n\ndef is_list_like_query_value(value: Any) -> bool:\n    return value is None or value == '' or isinstance(value, list)","tryCatchPattern":null,"preventionTips":["Encode statuses/sources with repeated params or array form on the client.","Run client requests through the generated OpenAPI schema validator.","Avoid hand-building query strings for list params."],"tags":["pydantic","validation","query-params","agent-roster"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}