{"record":{"id":"65da30bb119f7f80","repo":"moeru-ai/airi","slug":"the-base-url-is-not-an-absolute-http-or-https","errorCode":null,"errorMessage":"The Base URL is not an absolute http:// or https:// address.","messagePattern":"The Base URL is not an absolute http:// or https:// address\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/providers/providers/voicevox/engine.ts","lineNumber":189,"sourceCode":"  const body = await response.text()\n  try {\n    return JSON.parse(body) as T\n  }\n  catch {\n    throw new Error(`Speech engine answered /${endpoint} with a body that is not JSON. Check that the Base URL points at a VOICEVOX-compatible engine.`)\n  }\n}\n\nasync function request(\n  engineRequest: VoicevoxEngineRequest,\n  options?: VoicevoxEngineRequestOptions,\n): Promise<Response> {\n  let url: URL\n  try {\n    url = buildUrl(engineRequest)\n  }\n  catch {\n    throw new Error('The Base URL is not an absolute http:// or https:// address.')\n  }\n\n  const doFetch = options?.fetch ?? globalThis.fetch\n  const response = await doFetch(url, {\n    method: POST_ENDPOINTS.has(engineRequest.endpoint) ? 'POST' : 'GET',\n    // No engine in the family redirects. A redirect therefore means the Base URL\n    // points at something else, and following it would hide that.\n    redirect: 'error',\n    signal: options?.signal,\n    ...(engineRequest.body === undefined\n      ? {}\n      : { body: JSON.stringify(engineRequest.body), headers: { 'Content-Type': 'application/json' } }),\n  })\n\n  if (!response.ok) {\n    const detail = (await response.text()).trim()\n    const suffix = detail ? `: ${detail.slice(0, 200)}` : ''\n    throw new Error(`Speech engine answered ${response.status} ${response.statusText} for /${engineRequest.endpoint}${suffix}`)","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/stage-ui/src/libs/providers/providers/voicevox/engine.ts#L171-L207","documentation":"request() builds the target URL with `new URL(...)` via buildUrl; if that throws (base is relative, empty, or a non-http scheme), the library rethrows this error. The engine client requires an absolute http:// or https:// Base URL because the browser/renderer fetch cannot resolve engine-relative paths.","triggerScenarios":"Base URL configured as a relative path like `localhost:50021` (no scheme) or `/voicevox`, an empty string, or a scheme like `ws://`/`file://` — anything that makes `new URL(path, base)` throw or not be http(s).","commonSituations":"User typed the host without `http://`; trailing config value left empty after clearing a default; settings field trimmed of scheme; pasting a URL from docs that omitted the scheme.","solutions":["Set the Base URL to a full absolute URL including scheme, e.g. `http://127.0.0.1:50021` or `https://voicevox.example.com`.","If using a local engine on https-only pages, proxy it or use `http://localhost:50021` where allowed.","Trim whitespace and re-check the scheme when saving the settings field."],"exampleFix":"// before\nbaseUrl: 'localhost:50021'\n// after\nbaseUrl: 'http://localhost:50021'","handlingStrategy":"validation","validationCode":"function isAbsoluteHttpUrl(value: string): boolean {\n  try {\n    const url = new URL(value)\n    return url.protocol === 'http:' || url.protocol === 'https:'\n  }\n  catch {\n    return false\n  }\n}\nif (!isAbsoluteHttpUrl(baseUrl))\n  throw new Error('Base URL must be an absolute http:// or https:// address')","typeGuard":"function isHttpUrl(value: unknown): value is string {\n  if (typeof value !== 'string')\n    return false\n  try {\n    return ['http:', 'https:'].includes(new URL(value).protocol)\n  }\n  catch {\n    return false\n  }\n}","tryCatchPattern":null,"preventionTips":["Validate the Base URL field with an absolute-URL check at settings save time.","Show a hint/placeholder in the settings UI like `http://127.0.0.1:50021`.","Never build engine URLs by string concatenation on relative paths."],"tags":["configuration","url","voicevox","validation"],"backgroundTag":"invalid-base-url","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}