multica-ai/multica · error
invalid sort value
Error message
invalid sort value
What it means
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.
Source
Thrown at server/internal/handler/property.go:992
return "(" + strings.Join(groupSQL, " AND ") + ")"
}
// propertySortExpr resolves a `property:<definitionId>` sort value into a SQL
// ORDER BY expression. Returns handled=false when sortValue is not
// property-shaped (caller falls through to its static whitelist). A malformed
// id writes a 400 (ok=false). An unknown/archived definition or a type that
// has no meaningful order degrades to empty expr — callers keep position
// order, mirroring the frontend's stale-persisted-sort fallback rather than
// breaking installed clients with a 400.
func (h *Handler) propertySortExpr(r *http.Request, workspaceID string, sortValue string) (expr string, handled bool, err error) {
const prefix = "property:"
if !strings.HasPrefix(sortValue, prefix) {
return "", false, nil
}
rawID := strings.TrimPrefix(sortValue, prefix)
parsedID, parseErr := uuid.Parse(rawID)
if parseErr != nil {
return "", true, errors.New("invalid sort value")
}
wsUUID, wsErr := util.ParseUUID(workspaceID)
if wsErr != nil {
return "", true, errors.New("invalid workspace id")
}
var defUUID pgtype.UUID
copy(defUUID.Bytes[:], parsedID[:])
defUUID.Valid = true
def, dbErr := h.Queries.GetIssueProperty(r.Context(), db.GetIssuePropertyParams{ID: defUUID, WorkspaceID: wsUUID})
if dbErr != nil {
if errors.Is(dbErr, pgx.ErrNoRows) {
return "", true, nil // stale sort → position order
}
return "", true, fmt.Errorf("resolve sort property: %w", dbErr)
}
// Archived definitions degrade to position order like unknown ones —
// their values are hidden from the UI, so sorting by them would order
// the list by invisible data.View on GitHub (pinned to 2c0912b6ec)
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
Example fix
# before GET /api/issues?sort=property:name # after GET /api/issues?sort=property:550e8400-e29b-41d4-a716-446655440000
Defensive patterns
Strategy: validation
Validate before calling
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;
if (!PROPERTY_SORT_RE.test(sortValue)) delete params.sort; // or fix before sending Type guard
function isPropertySortValue(s: string): boolean {
const id = s.startsWith('property:') ? s.slice('property:'.length) : '';
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid workspace id
- expected a full UUID or at least %d hex characters, got %q
- expected a UUID prefix containing only hex characters, got %
- issue id is required
- issue ref %q looks like a short UUID prefix; short prefixes
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/fc6dbdb6b016565d.
Report an issue: GitHub.