{"record":{"id":"2c12c202b9037384","repo":"CherryHQ/cherry-studio","slug":"dmxapi-provider-requires-a-non-empty-baseurl-an","errorCode":null,"errorMessage":"DMXAPI provider requires a non-empty `baseURL`. An empty value would resolve fetch paths against the renderer process origin (app://, file://) and surface as opaque \"Failed to fetch\" errors.","messagePattern":"DMXAPI provider requires a non-empty `baseURL`\\. An empty value would resolve fetch paths against the renderer process origin \\(app://, file://\\) and surface as opaque \"Failed to fetch\" errors\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/provider/custom/dmxapi/dmxapiProvider.ts","lineNumber":110,"sourceCode":" * re-resolved provider settings.\n */\nexport function buildDmxapiTransport(settings: DmxapiProviderSettings): ImageGenerationTransport {\n  const chatBaseURL = settings.endpointBaseURLs?.[ENDPOINT_TYPE.OPENAI_CHAT_COMPLETIONS] ?? settings.baseURL\n  if (!chatBaseURL) {\n    throw new Error('DMXAPI provider requires a non-empty `baseURL` to build the image transport.')\n  }\n  return createDmxapiTransport({\n    apiKey: settings.apiKey ?? '',\n    // The transport POSTs to host-root paths (`/v1/images/...`), so strip the\n    // OpenAI-compat version suffix from the chat baseURL to avoid a double `/v1`.\n    baseURL: withoutTrailingApiVersion(chatBaseURL)\n  })\n}\n\nexport function createDmxapiProvider(settings: DmxapiProviderSettings = {}): DmxapiProvider {\n  const { baseURL, fetch: customFetch } = settings\n  if (!baseURL) {\n    throw new Error(\n      'DMXAPI provider requires a non-empty `baseURL`. An empty value would resolve fetch paths against the renderer process origin (app://, file://) and surface as opaque \"Failed to fetch\" errors.'\n    )\n  }\n\n  const resolveApiKey = () =>\n    loadApiKey({ apiKey: settings.apiKey, environmentVariableName: 'DMXAPI_API_KEY', description: 'DMXAPI' })\n\n  const compatHeaders = () => ({\n    Authorization: `Bearer ${resolveApiKey()}`,\n    ...settings.headers\n  })\n\n  const chatBaseURL = settings.endpointBaseURLs?.[ENDPOINT_TYPE.OPENAI_CHAT_COMPLETIONS] ?? baseURL\n  const compatUrl = ({ path }: { path: string; modelId: string }) => `${withoutTrailingSlash(chatBaseURL)}${path}`\n  const nativeBaseURL = withoutTrailingApiVersion(baseURL)\n  const anthropicBaseURL =\n    settings.endpointBaseURLs?.[ENDPOINT_TYPE.ANTHROPIC_MESSAGES] ?? formatApiHost(nativeBaseURL, true)\n  const geminiBaseURL =","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/provider/custom/dmxapi/dmxapiProvider.ts#L92-L128","documentation":"Thrown by `createDmxapiProvider` when `settings.baseURL` is falsy. Same Electron-origin rationale as the DashScope guard: an empty base would resolve fetch paths against the renderer origin (`app://`, `file://`) and surface as opaque \"Failed to fetch\" errors. Failing fast with an explicit message is preferred.","triggerScenarios":"Instantiating the DMXAPI provider with no `baseURL` — `createDmxapiProvider({})` or `createDmxapiProvider({ baseURL: '' })`.","commonSituations":"DMXAPI provider added in settings but the API host left blank; a migration reset the field; the user configured `endpointBaseURLs` only and expected the factory to infer a host.","solutions":["Set `baseURL` on the DMXAPI provider settings to the gateway host, e.g. `https://www.dmxapi.cn/v1`.","Confirm the provider config builder passes the host through from user settings.","Note: `endpointBaseURLs` supplements but does not replace `baseURL` for the factory guard."],"exampleFix":"// before\ncreateDmxapiProvider({ apiKey: 'sk-...' })\n// after\ncreateDmxapiProvider({ apiKey: 'sk-...', baseURL: 'https://www.dmxapi.cn/v1' })","handlingStrategy":"validation","validationCode":"function assertDmxapiSettings(s: { baseURL?: string }) {\n  if (!s.baseURL) throw new Error('DMXAPI baseURL required before creating provider')\n}\nassertDmxapiSettings(settings)\nconst provider = createDmxapiProvider(settings)","typeGuard":"const hasDmxapiBaseURL = (s: { baseURL?: string }): s is { baseURL: string } =>\n  typeof s.baseURL === 'string' && s.baseURL.trim().length > 0","tryCatchPattern":null,"preventionTips":["Make baseURL required in the DMXAPI settings schema","Validate provider config before factory creation","Note that endpointBaseURLs supplements but does not satisfy the factory guard"],"tags":["config","validation","dmxapi","base-url","electron"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}