{"record":{"id":"26db86f4b8c7cf78","repo":"linshenkx/prompt-optimizer","slug":"model-provider-cannot-be-empty","errorCode":null,"errorMessage":"Model provider cannot be empty","messagePattern":"Model provider cannot be empty","errorType":"validation","errorClass":"RequestConfigError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/llm/service.ts","lineNumber":85,"sourceCode":"      throw new RequestConfigError('Model provider metadata cannot be empty');\n    }\n    if (!modelConfig.modelMeta || !modelConfig.modelMeta.id) {\n      throw new RequestConfigError('Model metadata cannot be empty');\n    }\n    // Default behavior: disabled models cannot be used for normal requests.\n    // Connection testing is allowed to bypass this check (align with image model test behavior).\n    if (!options.allowDisabled && !modelConfig.enabled) {\n      throw new RequestConfigError('Model is not enabled');\n    }\n  }\n\n  /**\n   * 发送消息（结构化格式）\n   */\n  async sendMessageStructured(messages: Message[], provider: string): Promise<LLMResponse> {\n    try {\n      if (!provider) {\n        throw new RequestConfigError('Model provider cannot be empty');\n      }\n\n      const modelConfig = await this.modelManager.getModel(provider);\n      if (!modelConfig) {\n        throw new RequestConfigError(`Model ${provider} not found`);\n      }\n\n      this.validateModelConfig(modelConfig);\n      this.validateMessages(messages);\n\n      // 通过 Registry 获取 Adapter\n      const adapter = this.registry.getAdapter(modelConfig.providerMeta.id);\n\n      const runtimeConfig = this.prepareRuntimeConfig(modelConfig);\n\n      // 使用 Adapter 发送消息\n      return await adapter.sendMessage(messages, runtimeConfig);\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/llm/service.ts#L67-L103","documentation":"Thrown by sendMessageStructured when the provider argument is falsy. The service uses the provider id to resolve both the model config and the adapter, so an empty/undefined provider cannot proceed. This is a caller-side programming error, not an environmental issue.","triggerScenarios":"Calling sendMessageStructured(messages, '') , sendMessageStructured(messages, undefined), or with a variable that failed to populate (e.g. a settings read that returned undefined).","commonSituations":"Optional-chain reads like settings?.defaultProvider that silently yield undefined; UI state where the user hasn't selected a provider yet; refactors that changed the parameter from a config object to a plain provider string.","solutions":["Pass a non-empty provider id string matching a registered model (e.g. 'openai')","Default the value: provider ?? settings.defaultProvider ?? 'openai'","Guard the call site: if (!provider) return early with a user-facing prompt to pick a model"],"exampleFix":"// before\nconst provider = userSettings?.provider; // undefined\nawait llm.sendMessageStructured(msgs, provider);\n\n// after\nconst provider = userSettings?.provider ?? 'openai';\nif (!provider) throw new Error('Select a provider first');\nawait llm.sendMessageStructured(msgs, provider);","handlingStrategy":"type-guard","validationCode":"if (!provider || typeof provider !== 'string') throw new Error('Select a provider before sending');","typeGuard":"const isNonEmptyProvider = (p: unknown): p is string => typeof p === 'string' && p.length > 0;","tryCatchPattern":"catch (e) { if (e instanceof RequestConfigError && /provider cannot be empty/.test(e.message)) { /* surface 'pick a model' UI */ } }","preventionTips":["Default provider at the call site: provider ?? 'openai'","Disable send buttons until a provider is selected","Lint for forgotten optional chains when reading provider settings"],"tags":["llm","invalid-argument","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}