multica-ai/multica · error

invalid workspace id

Error message

invalid workspace id

What it means

propertySortExpr validates the workspace id from the request path/context with util.ParseUUID before resolving the sort property definition. A non-UUID workspaceID fails here. In normal routing the workspace id already passed middleware validation, so seeing this error usually means propertySortExpr was called with a wrong variable (empty string, slug, or name) rather than the routed UUID.

Source

Thrown at server/internal/handler/property.go:996

// 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.
	if def.ArchivedAt.Valid {
		return "", true, nil
	}
	// uuidToString re-serializes the parsed UUID: hex and dashes only, safe

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Ensure the request path carries the workspace UUID: /workspaces/{workspaceID}/issues?sort=property:<uuid>
  2. Check the chi route pattern includes {workspaceID} and the handler reads that exact param key
  3. In tests, generate a real UUID for the workspace fixture

Example fix

// before
sortExpr, handled, err := h.propertySortExpr(r, "", sortValue)
// after
sortExpr, handled, err := h.propertySortExpr(r, chi.URLParam(r, "workspaceID"), sortValue)
Defensive patterns

Strategy: validation

Validate before calling

import { UUID } from 'crypto';
if (!UUID_PATTERN.test(workspaceId)) throw new Error('workspace id must be a UUID');

Type guard

const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function isUuid(s: string): boolean { return UUID_PATTERN.test(s); }

Prevention

When it happens

Trigger: Calling propertySortExpr with an empty workspaceID (e.g. a route registered without the workspace-scoped middleware, or a handler reading the wrong URL param); passing a workspace slug like "my-team" where a UUID is expected.

Common situations: New endpoint wired into the property sort path without the {workspaceID} chi URL param; refactors that rename the route parameter; tests invoking the handler with placeholder strings.

Related errors


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