{"record":{"id":"75bb61b36c7d4903","repo":"can1357/oh-my-pi","slug":"destination-option-optionname-must-be-an-absolu","errorCode":null,"errorMessage":"Destination option ${optionName} must be an absolute HTTP URL","messagePattern":"Destination option (.+?) must be an absolute HTTP URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts","lineNumber":134,"sourceCode":"\nfunction encodedPath(parts: readonly string[]): string {\n\treturn parts.map(part => encodeURIComponent(part)).join(\"/\");\n}\n\nfunction endpoint(base: string, ...parts: string[]): string {\n\tconst url = new URL(base);\n\turl.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/${encodedPath(parts)}`;\n\turl.search = \"\";\n\turl.hash = \"\";\n\treturn url.toString();\n}\n\nfunction httpBase(value: string, optionName: string): URL {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new Error(`Destination option ${optionName} must be an absolute HTTP URL`);\n\t}\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new Error(`Destination option ${optionName} must use http or https`);\n\t}\n\treturn url;\n}\n\nfunction publicUrl(baseValue: string, directory: string | undefined, filename: string): string {\n\tconst url = httpBase(baseValue, \"publicBaseUrl\");\n\tconst relative = encodedPath([...pathParts(directory), filename]);\n\turl.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/${relative}`;\n\turl.hash = \"\";\n\treturn url.toString();\n}\n\nfunction basicAuthorization(username: string, password: string): string {\n\treturn `Basic ${Buffer.from(`${username}:${password}`, \"utf8\").toString(\"base64\")}`;\n}","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts#L116-L152","documentation":"Thrown by httpBase when a destination option that must be an absolute HTTP(S) URL (host base, apiUrl, publicBase, base) cannot be parsed by the URL constructor. The library builds API endpoints and public links from these bases, so they must be fully-qualified http:/https: URLs.","triggerScenarios":"Configuring an option like 'https:/host' (single slash), 'mycloud.example.com' (no scheme), 'ftp://host', 'localhost:8080' (parsed as scheme 'localhost:'), or an empty/typo'd string wherever httpBase validates it (url, createFtpUploader, createSharedFolderUploader, host, apiUrl, base).","commonSituations":"Omitting the scheme (bare hostname), using a protocol-relative '//host' value, typos like 'http//' or 'https:/', paste errors with surrounding quotes/spaces, or pointing an HTTP-based uploader at an ftp/s3 scheme URL.","solutions":["Add the scheme and both slashes: change 'mycloud.example.com' to 'https://mycloud.example.com'","Fix common typos: 'https:/host' -> 'https://host', remove trailing spaces or wrapping quotes","Use http:// only for local testing (e.g. http://localhost:8080); production should use https://","Pre-validate with `new URL(value)` and check protocol is http:/https: before saving the destination config"],"exampleFix":"// before\n{ \"apiUrl\": \"mycloud.example.com/ocs/v1.php\" }\n// after\n{ \"apiUrl\": \"https://mycloud.example.com/ocs/v1.php\" }","handlingStrategy":"validation","validationCode":"function assertHttpBase(value: string, optionName: string): void {\n  let u: URL;\n  try { u = new URL(value); } catch { throw new Error(`Destination option ${optionName} must be an absolute HTTP URL, got ${JSON.stringify(value)}`); }\n  if (u.protocol !== \"http:\" && u.protocol !== \"https:\") throw new Error(`Destination option ${optionName} must use http or https`);\n}\nassertHttpBase(destConfig.apiUrl, \"apiUrl\");","typeGuard":"function isHttpUrl(value: string): boolean {\n  try { const u = new URL(value); return u.protocol === \"http:\" || u.protocol === \"https:\"; } catch { return false; }\n}","tryCatchPattern":"try {\n  const uploader = createOwnCloudUploader(dest);\n} catch (err) {\n  const m = (err as Error).message.match(/Destination option (\\S+) must be an absolute HTTP URL/);\n  if (m) throw new Error(`Fix '${m[1]}' in your destination config — it must include a scheme, e.g. https://host`);\n  throw err;\n}","preventionTips":["Always include the scheme with two slashes: https://host, never bare hostname or 'https:/host'","Use http:// only for local testing; production bases should be https://","Run new URL(value) on every URL-shaped config option at config-load time","Trim whitespace and strip stray quotes before storing URL options"],"tags":["configuration","url","validation","self-hosted"],"backgroundTag":"invalid-url-config","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}