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

  1. Send the full property definition UUID: sort=property:550e8400-e29b-41d4-a716-446655440000
  2. Fetch property definitions first and use the returned id verbatim
  3. 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

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


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/fc6dbdb6b016565d. Report an issue: GitHub.