{"record":{"id":"9b467c41fa15b2b7","repo":"linshenkx/prompt-optimizer","slug":"model-metadata-cannot-be-empty-9b467c","errorCode":null,"errorMessage":"Model metadata cannot be empty","messagePattern":"Model metadata cannot be empty","errorType":"validation","errorClass":"RequestConfigError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/llm/service.ts","lineNumber":70,"sourceCode":"      }\n    });\n  }\n\n  /**\n   * 验证模型配置\n   */\n  private validateModelConfig(\n    modelConfig: TextModelConfig,\n    options: { allowDisabled?: boolean } = {}\n  ): void {\n    if (!modelConfig) {\n      throw new RequestConfigError('Model config cannot be empty');\n    }\n    if (!modelConfig.providerMeta || !modelConfig.providerMeta.id) {\n      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);","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/llm/service.ts#L52-L88","documentation":"Thrown by validateModelConfig when the model config has no modelMeta or modelMeta.id. The service needs the model metadata (e.g. model name 'gpt-4o') to build the runtime request payload. A config missing modelMeta cannot produce a valid completion request.","triggerScenarios":"Calling sendMessageStructured, sendMessageStream, sendMessageStreamWithTools, or testConnection where modelManager.getModel(provider) returns a config with modelMeta undefined or modelMeta.id empty. Common with hand-built configs or configs deserialized from older storage formats.","commonSituations":"Partial config objects in unit tests; JSON configs where the model identifier field was renamed; configs created via a UI flow that saved before the model was selected; imports from another tool that only capture provider info.","solutions":["Ensure the config includes modelMeta: { id: '<model-name>' } with a non-empty id","Verify the UI/seed flow persists modelMeta alongside providerMeta","Validate configs once at load time and reject/repair entries missing modelMeta before runtime calls"],"exampleFix":"// before\nconst config = { providerMeta: { id: 'openai' } };\n\n// after\nconst config = { providerMeta: { id: 'openai' }, modelMeta: { id: 'gpt-4o' } };","handlingStrategy":"validation","validationCode":"function hasModelMeta(c: ModelConfig | undefined | null): boolean {\n  return !!c && !!c.modelMeta && !!c.modelMeta.id;\n}","typeGuard":"function isCompleteModelConfig(c: unknown): c is ModelConfig {\n  const m = c as ModelConfig;\n  return !!m?.providerMeta?.id && !!m?.modelMeta?.id;\n}","tryCatchPattern":"catch (e) { if (e instanceof RequestConfigError && /Model metadata/.test(e.message)) { /* prompt model selection / repair config */ } }","preventionTips":["Require model selection before saving a provider config","Schema-validate persisted config JSON (e.g. zod) at load time","Test config round-trip (save → load) in CI"],"tags":["llm","configuration","model-config","validation"],"backgroundTag":"invalid-model-configuration","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}