{"record":{"id":"6c837fd503ee5760","repo":"multica-ai/multica","slug":"value-must-be-a-url-string","errorCode":null,"errorMessage":"value must be a URL string","messagePattern":"value must be a URL string","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/internal/handler/property.go","lineNumber":332,"sourceCode":"\n\tcfg := parsePropertyConfig(def.Config)\n\tswitch def.Type {\n\tcase \"text\":\n\t\ts, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"value must be a string\")\n\t\t}\n\t\tif strings.TrimSpace(s) == \"\" {\n\t\t\treturn nil, errors.New(\"value cannot be empty (use DELETE to unset a property)\")\n\t\t}\n\t\tif utf8.RuneCountInString(s) > maxPropertyTextValueLen {\n\t\t\treturn nil, fmt.Errorf(\"value must be %d characters or fewer\", maxPropertyTextValueLen)\n\t\t}\n\t\treturn json.Marshal(sanitizeNullBytes(s))\n\tcase \"url\":\n\t\ts, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"value must be a URL string\")\n\t\t}\n\t\ts = strings.TrimSpace(s)\n\t\tif len(s) > maxPropertyURLValueLen {\n\t\t\treturn nil, fmt.Errorf(\"value must be %d characters or fewer\", maxPropertyURLValueLen)\n\t\t}\n\t\tu, err := url.Parse(s)\n\t\tif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || u.Host == \"\" {\n\t\t\treturn nil, errors.New(\"value must be an http(s) URL\")\n\t\t}\n\t\treturn json.Marshal(s)\n\tcase \"number\":\n\t\tif _, ok := v.(float64); !ok {\n\t\t\treturn nil, errors.New(\"value must be a number\")\n\t\t}\n\t\treturn json.Marshal(v)\n\tcase \"checkbox\":\n\t\tif _, ok := v.(bool); !ok {\n\t\t\treturn nil, errors.New(\"value must be true or false\")","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/handler/property.go#L314-L350","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Coerce the value to a string before sending: String(value) or url.href","Fix the client payload type so value is typed string for url properties","If the property should hold numbers, change the property definition type to \"number\" in workspace settings"],"exampleFix":"// before\n{ value: new URL(\"https://example.com\") } // serializes to {}\n// after\n{ value: \"https://example.com\" }","handlingStrategy":"type-guard","validationCode":"if (def.type === 'url' && typeof value !== 'string') {\n  throw new Error(`Property ${def.name} expects a URL string`);\n}","typeGuard":"function isUrlPropertyValue(v: unknown): v is string {\n  return typeof v === 'string';\n}","tryCatchPattern":"try { await updateProperty(payload); }\ncatch (e) { if (e.status === 400 && e.message.includes('URL string')) fixPayloadType(); else throw e; }","preventionTips":["Type the request payload per property definition type, not as any","Stringify URL objects to .href before sending","Validate against the property definition's type fetched from the API"],"tags":["validation","url","issue-properties"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}