multica-ai/multica · error

value must be a URL string

Error message

value must be a URL string

What it means

validatePropertyValue rejects a URL-type property value that is not a JSON string — for example a number, object, array, or boolean. The property definition declares type "url", so the stored value must be a string that is later parsed and scheme-checked. Returned as a 400 from the property update endpoint.

Source

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

	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")
		}
		return json.Marshal(s)
	case "number":
		if _, ok := v.(float64); !ok {
			return nil, errors.New("value must be a number")
		}
		return json.Marshal(v)
	case "checkbox":
		if _, ok := v.(bool); !ok {
			return nil, errors.New("value must be true or false")

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Coerce the value to a string before sending: String(value) or url.href
  2. Fix the client payload type so value is typed string for url properties
  3. If the property should hold numbers, change the property definition type to "number" in workspace settings

Example fix

// before
{ value: new URL("https://example.com") } // serializes to {}
// after
{ value: "https://example.com" }
Defensive patterns

Strategy: type-guard

Validate before calling

if (def.type === 'url' && typeof value !== 'string') {
  throw new Error(`Property ${def.name} expects a URL string`);
}

Type guard

function isUrlPropertyValue(v: unknown): v is string {
  return typeof v === 'string';
}

Try / catch

try { await updateProperty(payload); }
catch (e) { if (e.status === 400 && e.message.includes('URL string')) fixPayloadType(); else throw e; }

Prevention

When it happens

Trigger: PUT/PATCH an issue property of type "url" with {"value": 12345}, {"value": {"url": "..."}}, or {"value": ["https://..."]}. Common when a client builds the payload from untyped form data and a number or nested object slips through.

Common situations: Sending an already-parsed URL object (e.g. new URL(...) serialized wrong) instead of href; TypeScript any payloads hiding a non-string; form libraries that coerce numeric-looking input ('123') inconsistently.

Related errors


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