{"record":{"id":"b424c682af772ea9","repo":"iOfficeAI/AionUi","slug":"update-errors-invalidurl","errorCode":"update.errors.invalidUrl","errorMessage":"update.errors.invalidUrl","messagePattern":"update\\.errors\\.invalidUrl","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/desktop/src/process/bridge/updateBridge.ts","lineNumber":275,"sourceCode":"    prerelease: false,\n    draft: false,\n    assets,\n    recommendedAsset: pickRecommendedAsset(assets),\n  };\n};\n\nconst resolveRepo = (requestRepo?: string): string => {\n  const envRepo = process.env.AIONUI_GITHUB_REPO?.trim();\n  const repo = (requestRepo || envRepo || DEFAULT_REPO).trim();\n  return repo || DEFAULT_REPO;\n};\n\nconst assertAllowedUrl = async (rawUrl: string) => {\n  let parsed: URL;\n  try {\n    parsed = new URL(rawUrl);\n  } catch {\n    throw new Error((await getI18n()).t('update.errors.invalidUrl'));\n  }\n\n  if (parsed.protocol !== 'https:') {\n    throw new Error((await getI18n()).t('update.errors.httpsOnly'));\n  }\n  if (!ALLOWED_DOWNLOAD_HOSTS.has(parsed.hostname)) {\n    throw new Error((await getI18n()).t('update.errors.hostNotAllowed', { host: parsed.hostname }));\n  }\n};\n\nconst fetchWithAllowlistedRedirects = async (rawUrl: string, signal: AbortSignal): Promise<Response> => {\n  let current = rawUrl;\n\n  for (let i = 0; i <= MAX_REDIRECTS; i++) {\n    await assertAllowedUrl(current);\n\n    const res = await fetch(current, {\n      signal,","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/iOfficeAI/AionUi/blob/711aa0550ee183ea495dc33e2c05c7943b70a60a/packages/desktop/src/process/bridge/updateBridge.ts#L257-L293","documentation":"Thrown by assertAllowedUrl in the update bridge when the URL string passed to the updater cannot be parsed by the URL constructor. It is the first validation step before protocol and host checks, so any syntactically invalid URL (empty string, missing scheme, malformed characters) triggers it.","triggerScenarios":"Calling any update API that funnels through assertAllowedUrl (fetchWithAllowlistedRedirects, runWithFallback, initUpdateBridge) with a non-URL string: '', 'github.com/owner/repo' (no scheme), 'https://' alone, or a URL with invalid control characters.","commonSituations":"A misconfigured update feed URL in settings/config that omits https://; a template string that evaluated to undefined and became 'undefined'; trailing whitespace or newline in a config-provided URL; corrupted persisted app config after an upgrade.","solutions":["Check the URL string being passed — it must be a fully qualified absolute URL","Add the https:// scheme if it is missing","Trim whitespace/newlines from config-sourced URLs before passing them","Reset or fix the stored update configuration if it was corrupted","Log the raw value before the call to identify where the bad string originates"],"exampleFix":"// before\nawait assertAllowedUrl(feedUrl); // feedUrl = 'example.com/app.json'\n\n// after\nconst normalized = feedUrl.trim();\nawait assertAllowedUrl(\n  /^https?:\\/\\//.test(normalized) ? normalized : `https://${normalized}`,\n);","handlingStrategy":"validation","validationCode":"const isValidAbsoluteUrl = (s: string): boolean => {\n  try {\n    const u = new URL(s.trim());\n    return u.protocol === 'http:' || u.protocol === 'https:';\n  } catch {\n    return false;\n  }\n};\nif (!isValidAbsoluteUrl(feedUrl)) throw new Error('configure a valid https update URL');\nawait initUpdateBridge(feedUrl);","typeGuard":"const isParsableUrl = (v: unknown): v is string =>\n  typeof v === 'string' &&\n  (() => { try { new URL(v.trim()); return true; } catch { return false; } })();","tryCatchPattern":"try {\n  await assertAllowedUrl(url);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('invalidUrl')) {\n    // sanitize: trim, prepend https:// if scheme missing, then retry\n  } else throw err;\n}","preventionTips":["Always store fully-qualified https URLs in update config","Trim config-sourced URLs before use","Fail fast in settings UI when the URL field cannot be parsed by new URL()","Never build feed URLs from possibly-undefined template variables"],"tags":["url-validation","updater","config"],"backgroundTag":"invalid-url","analyzedSha":"711aa0550ee183ea495dc33e2c05c7943b70a60a","analyzedAt":"2026-08-28T07:56:06.558Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}