{"record":{"id":"160e5936ff7105b6","repo":"router-for-me/CLIProxyAPI","slug":"invalid-plugin-store-url","errorCode":null,"errorMessage":"invalid plugin store url","messagePattern":"invalid plugin store url","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"internal/pluginstore/auth.go","lineNumber":313,"sourceCode":"\t\theaders.Set(\"Authorization\", \"Basic \"+encoded)\n\tcase AuthTypeHeader:\n\t\tif strings.TrimSpace(item.HeaderName) == \"\" {\n\t\t\treturn false, fmt.Errorf(\"plugin store resolved auth missing header-name\")\n\t\t}\n\t\tif len(item.HeaderValue) == 0 {\n\t\t\treturn false, fmt.Errorf(\"plugin store resolved auth header value is empty\")\n\t\t}\n\t\theaders.Set(item.HeaderName, string(item.HeaderValue))\n\tdefault:\n\t\treturn false, fmt.Errorf(\"unsupported plugin store resolved auth type %q\", item.Type)\n\t}\n\treturn true, nil\n}\n\nfunc validatePluginStoreRequestURL(auth []AuthConfig, requestURL string, kind string) error {\n\tparsed, errParse := url.Parse(strings.TrimSpace(requestURL))\n\tif errParse != nil || parsed.Scheme == \"\" || parsed.Host == \"\" {\n\t\treturn fmt.Errorf(\"invalid plugin store url\")\n\t}\n\tif parsed.User != nil {\n\t\treturn fmt.Errorf(\"plugin store url must not contain credentials\")\n\t}\n\tif hasSensitiveQueryParameter(parsed) {\n\t\treturn fmt.Errorf(\"plugin store url contains sensitive query parameter\")\n\t}\n\tif strings.EqualFold(parsed.Scheme, \"http\") && !allowInsecurePluginStoreURL(auth, requestURL, kind) {\n\t\treturn fmt.Errorf(\"insecure plugin store url requires matching allow-insecure auth rule\")\n\t}\n\treturn nil\n}\n\nfunc allowInsecurePluginStoreURL(auth []AuthConfig, requestURL string, kind string) bool {\n\titem, ok := matchingAuthConfig(auth, requestURL, kind)\n\treturn ok && item.AllowInsecure\n}\n","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/auth.go#L295-L331","documentation":"validatePluginStoreRequestURL rejected a plugin store URL: url.Parse failed, or the parsed URL has no scheme or no host. The pluginstore client refuses to fetch registry/metadata/artifact resources from URLs it cannot positively identify, as a precondition before any auth or HTTP work. Typical causes are malformed URLs, missing https://, or a variable that expanded to a partial string.","triggerScenarios":"Calling a store fetch (registry.json, metadata, artifact download) with a URL like 'plugins.example.com/index.json' (no scheme), 'https:///path' (no host), or a value containing characters that make url.Parse error.","commonSituations":"Registry URL copied without the scheme; template variable for the store base URL empty so the path alone remains; trailing control characters or spaces beyond trimming; custom plugin store configured by hand in config.yaml.","solutions":["Write the full absolute URL including scheme and host, e.g. https://plugins.example.com/registry.json","Print/inspect the effective URL at runtime to catch empty variable substitution","Validate store URLs with url.Parse in a pre-flight check before configuring"],"exampleFix":"# before\nurl: plugins.example.com/plugins/index.json\n\n# after\nurl: https://plugins.example.com/plugins/index.json","handlingStrategy":"validation","validationCode":"func validStoreURL(raw string) error {\n\tu, err := url.Parse(strings.TrimSpace(raw))\n\tif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n\t\treturn fmt.Errorf(\"store URL %q must be absolute with scheme and host\", raw)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always configure full absolute URLs (scheme + host) for store endpoints","Add a config lint step that url.Parse's every store URL and rejects empty scheme/host"],"tags":["url","config","plugin-store","validation"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}