multica-ai/multica · error

value cannot be empty (use DELETE to unset a property)

Error message

value cannot be empty (use DELETE to unset a property)

What it means

Thrown by validatePropertyValue in the Multica server when a property of type "text" is set to a string that is empty or only whitespace. The API treats JSON null as 'unset this property' and rejects empty strings instead of silently clearing them, so unsetting must go through the DELETE verb. It is returned as a 400-class validation error from the issue property update endpoint.

Source

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

		return nil, errors.New("value is required")
	}
	var v any
	if err := json.Unmarshal(raw, &v); err != nil {
		return nil, fmt.Errorf("value must be valid JSON: %w", err)
	}
	if v == nil {
		return nil, errors.New("value cannot be null (use DELETE to unset a property)")
	}

	cfg := parsePropertyConfig(def.Config)
	switch def.Type {
	case "text":
		s, ok := v.(string)
		if !ok {
			return nil, errors.New("value must be a string")
		}
		if strings.TrimSpace(s) == "" {
			return nil, errors.New("value cannot be empty (use DELETE to unset a property)")
		}
		if utf8.RuneCountInString(s) > maxPropertyTextValueLen {
			return nil, fmt.Errorf("value must be %d characters or fewer", maxPropertyTextValueLen)
		}
		return json.Marshal(sanitizeNullBytes(s))
	case "url":
		s, ok := v.(string)
		if !ok {
			return nil, errors.New("value must be a URL string")
		}
		s = strings.TrimSpace(s)
		if len(s) > maxPropertyURLValueLen {
			return nil, fmt.Errorf("value must be %d characters or fewer", maxPropertyURLValueLen)
		}
		u, err := url.Parse(s)
		if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
			return nil, errors.New("value must be an http(s) URL")
		}

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Send JSON null (or omit value) to clear the field, or use the DELETE endpoint for the property
  2. Guard in the client: if the trimmed text is empty, issue DELETE instead of a value update
  3. Keep a non-empty placeholder value if the property is required by workflow

Example fix

// before
await api.updateIssueProperty(issueId, propId, { value: "" });
// after
await api.deleteIssueProperty(issueId, propId); // or send { value: null } per API contract
Defensive patterns

Strategy: validation

Validate before calling

const v = req.value;
if (typeof v === 'string' && v.trim() === '') {
  // empty text means unset -> route to DELETE
  await api.deleteIssueProperty(issueId, propId);
  return;
}

Type guard

function isEmptyTextValue(v: unknown): boolean {
  return typeof v === 'string' && v.trim() === '';
}

Try / catch

try { await api.updateIssueProperty(id, propId, { value }); }
catch (e) {
  if (e.status === 400 && /cannot be empty/.test(e.message)) await api.deleteIssueProperty(id, propId);
  else throw e;
}

Prevention

When it happens

Trigger: PUT/PATCH on an issue property whose definition type is "text" with req.Value = "" or " " (e.g. {"value": ""} in the property value update payload handled at property.go:762). Happens when a form submits an untouched-but-touched-and-cleared input, or when code trims a value to nothing before sending.

Common situations: Frontend forms that send the current field value on blur/save even when the user cleared it; import scripts mapping blank CSV cells to empty strings instead of null; a toggle from 'has value' to 'cleared' implemented as empty-string instead of DELETE.

Related errors


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