{"record":{"id":"fe2cb74a1b97b239","repo":"langgenius/dify","slug":"sort-by-must-be-created-at-or-updated-at","errorCode":null,"errorMessage":"sort_by must be created_at or updated_at","messagePattern":"sort_by must be created_at or updated_at","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"api/controllers/console/agent/roster.py","lineNumber":212,"sourceCode":"        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\nclass AgentStatisticsQuery(BaseModel):\n    source: str | None = Field(\n        default=None,\n        description=(\n            \"Filter by a structured webapp:<app_id> or workflow:<app_id> source ID. \"\n            \"Legacy invoke sources and exact workflow version/node source IDs remain supported.\"\n        ),","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/agent/roster.py#L194-L230","documentation":"A Pydantic field_validator on RosterListQuery.sort_by: the value (trimmed, lowercased) must be one of {created_at, updated_at}. Any other value is rejected with a 422. The validator normalizes case/whitespace first, so ' Updated_At ' is accepted but 'name' or 'createdAt' is not.","triggerScenarios":"GET /console/agents with ?sort_by=<anything else>, e.g. ?sort_by=name, ?sort_by=createdAt, ?sort_by=published_at. Common when a generic table component passes the column key verbatim.","commonSituations":"Frontend table that sends camelCase column keys (createdAt) instead of snake_case; a client built against a different API that allowed other sort fields; typo in the param.","solutions":["Send ?sort_by=created_at or ?sort_by=updated_at (case-insensitive, trimmed).","Map frontend column keys to the allowed enum before submitting the query.","Omit sort_by to use the default (updated_at).","Update the client's sort field allowlist from the schema."],"exampleFix":"// before\nquery.sort_by = 'createdAt'\n// after\nquery.sort_by = 'created_at'","handlingStrategy":"validation","validationCode":"ALLOWED_SORT_BY = {'created_at', 'updated_at'}\n\ndef normalize_sort_by(value: str) -> str:\n    norm = (value or '').strip().lower()\n    return norm if norm in ALLOWED_SORT_BY else 'updated_at'","typeGuard":"def is_valid_sort_by(value: str) -> bool:\n    return isinstance(value, str) and value.strip().lower() in {'created_at', 'updated_at'}","tryCatchPattern":null,"preventionTips":["Map UI column keys to the {created_at, updated_at} enum before sending.","Omit sort_by to fall back to the default (updated_at).","Keep the client's sort-field allowlist in sync with the schema."],"tags":["pydantic","validation","query-params","agent-roster","sorting"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}