{"record":{"id":"025373e8a8b44b00","repo":"multica-ai/multica","slug":"invalid-multica-server-url-w","errorCode":null,"errorMessage":"invalid MULTICA_SERVER_URL: %w","messagePattern":"invalid MULTICA_SERVER_URL: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/config.go","lineNumber":579,"sourceCode":"// isOfficialCloudServer reports whether the resolved server base URL points\n// at Multica's hosted cloud. Used to pick the auto-update default: cloud\n// users run a server that publishes the matching CLI release, so opt-in\n// self-update is safe; self-host users may run a fork or pin to an older\n// server, so the default flips to off. Matching is host-only and\n// case-insensitive — port and path are ignored.\nfunc isOfficialCloudServer(baseURL string) bool {\n\tu, err := url.Parse(strings.TrimSpace(baseURL))\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn strings.EqualFold(u.Hostname(), officialCloudHost)\n}\n\n// NormalizeServerBaseURL converts a WebSocket or HTTP URL to a base HTTP URL.\nfunc NormalizeServerBaseURL(raw string) (string, error) {\n\tu, err := url.Parse(strings.TrimSpace(raw))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid MULTICA_SERVER_URL: %w\", err)\n\t}\n\tswitch u.Scheme {\n\tcase \"ws\":\n\t\tu.Scheme = \"http\"\n\tcase \"wss\":\n\t\tu.Scheme = \"https\"\n\tcase \"http\", \"https\":\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"MULTICA_SERVER_URL must use ws, wss, http, or https\")\n\t}\n\tif u.Path == \"/ws\" {\n\t\tu.Path = \"\"\n\t}\n\tu.RawPath = \"\"\n\tu.RawQuery = \"\"\n\tu.Fragment = \"\"\n\treturn strings.TrimRight(u.String(), \"/\"), nil\n}","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/config.go#L561-L597","documentation":"NormalizeServerBaseURL failed at the first step: url.Parse rejected the trimmed MULTICA_SERVER_URL value. The Go URL parser is lenient, so this only happens with genuinely malformed input (control characters, an unmatched '%' escape, or embedded whitespace that survives trimming at the ends). The error wraps the parse error so the exact position is visible.","triggerScenarios":"Setting MULTICA_SERVER_URL to a value containing a raw '%' (e.g. a password with %zz in it), control characters from a copy-paste, or a trailing/leading quote from shell wrapping. Note that values like 'localhost:8080' parse fine and instead fail the scheme check (error 872).","commonSituations":"Copy-paste from docs with smart quotes/invisible characters, shell quoting mistakes leaving a stray quote inside the value, secrets or malformed escapes embedded in the URL.","solutions":["Print the value with %q to reveal invisible characters: it usually shows a quote, control rune, or raw %","Re-enter the URL as plain https://host[:port] with no quotes or escapes inside the value","URL-encode any legitimate special characters (a '%' must be '%25')"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate the env var before passing it on.\nraw := strings.TrimSpace(os.Getenv(\"MULTICA_SERVER_URL\"))\nif u, err := url.Parse(raw); err != nil {\n    return fmt.Errorf(\"MULTICA_SERVER_URL %q is not a parseable URL: %w\", raw, err)\n}","typeGuard":null,"tryCatchPattern":"Handle at config-load time: catch the error, echo the raw value with %q so hidden characters are visible, and prompt the user to re-enter it.","preventionTips":["Avoid pasting URLs from rich-text sources","URL-encode special characters ('%' as '%25')","Lint env files for control characters in CI"],"tags":["daemon","config","url","env-var"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}