{"record":{"id":"fc6dbdb6b016565d","repo":"multica-ai/multica","slug":"invalid-sort-value","errorCode":null,"errorMessage":"invalid sort value","messagePattern":"invalid sort value","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/internal/handler/property.go","lineNumber":992,"sourceCode":"\treturn \"(\" + strings.Join(groupSQL, \" AND \") + \")\"\n}\n\n// propertySortExpr resolves a `property:<definitionId>` sort value into a SQL\n// ORDER BY expression. Returns handled=false when sortValue is not\n// property-shaped (caller falls through to its static whitelist). A malformed\n// id writes a 400 (ok=false). An unknown/archived definition or a type that\n// has no meaningful order degrades to empty expr — callers keep position\n// order, mirroring the frontend's stale-persisted-sort fallback rather than\n// breaking installed clients with a 400.\nfunc (h *Handler) propertySortExpr(r *http.Request, workspaceID string, sortValue string) (expr string, handled bool, err error) {\n\tconst prefix = \"property:\"\n\tif !strings.HasPrefix(sortValue, prefix) {\n\t\treturn \"\", false, nil\n\t}\n\trawID := strings.TrimPrefix(sortValue, prefix)\n\tparsedID, parseErr := uuid.Parse(rawID)\n\tif parseErr != nil {\n\t\treturn \"\", true, errors.New(\"invalid sort value\")\n\t}\n\twsUUID, wsErr := util.ParseUUID(workspaceID)\n\tif wsErr != nil {\n\t\treturn \"\", true, errors.New(\"invalid workspace id\")\n\t}\n\tvar defUUID pgtype.UUID\n\tcopy(defUUID.Bytes[:], parsedID[:])\n\tdefUUID.Valid = true\n\tdef, dbErr := h.Queries.GetIssueProperty(r.Context(), db.GetIssuePropertyParams{ID: defUUID, WorkspaceID: wsUUID})\n\tif dbErr != nil {\n\t\tif errors.Is(dbErr, pgx.ErrNoRows) {\n\t\t\treturn \"\", true, nil // stale sort → position order\n\t\t}\n\t\treturn \"\", true, fmt.Errorf(\"resolve sort property: %w\", dbErr)\n\t}\n\t// Archived definitions degrade to position order like unknown ones —\n\t// their values are hidden from the UI, so sorting by them would order\n\t// the list by invisible data.","sourceCodeStart":974,"sourceCodeEnd":1010,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/handler/property.go#L974-L1010","documentation":"propertySortExpr parses the sort parameter prefix \"property:<uuid>\" on issue list queries. When the segment after the prefix is not a valid UUID, the sort is treated as an attempted property sort and rejected rather than silently ignored — the function's contract returns handled=true so the caller turns this into a 400 instead of falling back to default ordering.","triggerScenarios":"GET /issues?sort=property:abc, sort=property: (empty id), sort=property:%20 or a truncated/corrupted persisted sort string from a client's local storage sent back as a query parameter.","commonSituations":"A frontend persisting sort state that got truncated; hand-built URLs with typos; older clients using a pre-UUID property identifier format after an upgrade; URL encoding artifacts.","solutions":["Send the full property definition UUID: sort=property:550e8400-e29b-41d4-a716-446655440000","Fetch property definitions first and use the returned id verbatim","If you want the default order, omit the sort parameter entirely instead of sending a malformed one"],"exampleFix":"# before\nGET /api/issues?sort=property:name\n# after\nGET /api/issues?sort=property:550e8400-e29b-41d4-a716-446655440000","handlingStrategy":"validation","validationCode":"const PROPERTY_SORT_RE = /^property:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nif (!PROPERTY_SORT_RE.test(sortValue)) delete params.sort; // or fix before sending","typeGuard":"function isPropertySortValue(s: string): boolean {\n  const id = s.startsWith('property:') ? s.slice('property:'.length) : '';\n  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n}","tryCatchPattern":null,"preventionTips":["Persist the property UUID from the API response, never a name","Validate persisted sort strings against a versioned schema before replaying them","Drop unknown sort values client-side instead of forwarding them"],"tags":["validation","sort","uuid","issues"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}