{"record":{"id":"6573ec1a63b92c8d","repo":"musistudio/claude-code-router","slug":"provider-manifest-url-is-invalid","errorCode":null,"errorMessage":"Provider manifest URL is invalid.","messagePattern":"Provider manifest URL is invalid\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/contracts/deep-link.ts","lineNumber":487,"sourceCode":"  const url = new URL(providerUrlWithDefaultScheme(value));\n  if (![\"http:\", \"https:\"].includes(url.protocol)) {\n    throw new Error(\"Provider Base URL must use http or https.\");\n  }\n  if (!url.hostname) {\n    throw new Error(\"Provider Base URL is invalid.\");\n  }\n}\n\nfunction validateManifestUrl(value: string): void {\n  const url = new URL(value);\n  if (url.protocol !== \"https:\") {\n    throw new Error(\"Provider manifest URL must use https.\");\n  }\n  if (url.username || url.password) {\n    throw new Error(\"Provider manifest URL cannot include credentials.\");\n  }\n  if (!url.hostname) {\n    throw new Error(\"Provider manifest URL is invalid.\");\n  }\n}\n\nfunction normalizeProviderProtocol(value: string | undefined): GatewayProviderProtocol | undefined {\n  if (!value) {\n    return undefined;\n  }\n  const protocol = value.trim();\n  if (!providerProtocols.has(protocol as GatewayProviderProtocol)) {\n    throw new Error(`Unsupported provider protocol: ${value}`);\n  }\n  return protocol as GatewayProviderProtocol;\n}\n\nfunction readDeepLinkModels(params: URLSearchParams, payload: Record<string, unknown> | undefined): string[] {\n  const values = [\n    ...params.getAll(\"models\"),\n    ...payloadModels(payload)","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/contracts/deep-link.ts#L469-L505","documentation":"The final manifest URL check requires a hostname: an https URL like \"https:///m.json\" parses successfully but has an empty host, so the manifest cannot be fetched and the URL is declared invalid.","triggerScenarios":"A manifest param whose URL has no hostname, e.g. https:///provider.json or https://:8443/m.json.","commonSituations":"Link generators interpolating an unset host variable; truncated copy-paste losing the domain; malformed template output.","solutions":["Include the full host: https://cdn.example.com/provider/manifest.json","Assert the composed URL has a hostname before embedding it in links","Set missing env/config values used to build the manifest URL"],"exampleFix":"// before\nmanifest=https%3A%2F%2F%2Fprovider.json\n// after\nmanifest=https%3A%2F%2Fcdn.example.com%2Fprovider.json","handlingStrategy":"validation","validationCode":"if (!new URL(manifestUrl).hostname) return reject(\"manifest URL missing host\");","typeGuard":"const manifestUrlHasHost = (u: string) => { try { return new URL(u).hostname.length > 0; } catch { return false; } };","tryCatchPattern":"try { parseProviderManifestDeepLinkPayload(url); } catch (e) { if (e instanceof Error && e.message === \"Provider manifest URL is invalid.\") return askForManifestUrl(); throw e; }","preventionTips":["Compose manifest URLs from validated host config","Assert hostname presence in link builders"],"tags":["manifest","validation","hostname"],"backgroundTag":"invalid-url-host","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}