{"record":{"id":"79cc23e3b65cd081","repo":"linshenkx/prompt-optimizer","slug":"config-invalid","errorCode":"CONFIG_INVALID","errorMessage":"Missing provider/model identity","messagePattern":"Missing provider/model identity","errorType":"error_code","errorClass":"ImageModelManagerError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/image-model/manager.ts","lineNumber":410,"sourceCode":"    }\n\n    // 合并 customParamOverrides 到 paramOverrides\n    return {\n      ...config,\n      paramOverrides: {\n        ...(config.paramOverrides || {}),\n        ...(config.customParamOverrides || {})\n      }\n      // 保留 customParamOverrides 字段以防版本回退，但新代码不再使用\n    }\n  }\n\n  private getConfigIdentity(config: ImageModelConfigInput): { providerId: string, modelId: string } {\n    const providerId = config.providerId || config.provider?.id || config.model?.providerId\n    const modelId = config.modelId || config.model?.id\n\n    if (!providerId || !modelId) {\n      throw new ImageModelManagerError(\n        IMAGE_ERROR_CODES.CONFIG_INVALID,\n        'Missing provider/model identity',\n        { details: 'Missing providerId/modelId' },\n      )\n    }\n\n    return { providerId, modelId }\n  }\n\n  // 确保配置是自包含的（包含完整的provider和model信息）\n  private ensureSelfContained(config: ImageModelConfigInput): ImageModelConfig {\n    let identity: { providerId: string, modelId: string }\n\n    try {\n      identity = this.getConfigIdentity(config)\n    } catch (error) {\n      console.warn(`[ImageModelManager] Cannot infer identity for config ${config.id}, marking as disabled:`, error)\n      identity = {","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/image-model/manager.ts#L392-L428","documentation":"Thrown by ImageModelManager.getConfigIdentity when a config carries neither providerId/provider.id nor modelId/model.id. The manager needs a (providerId, modelId) pair to key, deduplicate, and persist configs, and ensureSelfContained calls this during import/registration to verify the identity is present.","triggerScenarios":"Passing a config where providerId and provider?.id are both falsy, or modelId and model?.id are both falsy — e.g. { modelId: 'x' } with no provider fields, or { provider: { name: 'openai' } } with an id-less provider object.","commonSituations":"Building a config from a UI form where the provider select was left empty; partial configs from external sources that carry only a model name; refactors that renamed id fields.","solutions":["Set providerId (or provider.id) and modelId (or model.id) explicitly on the config before calling the API.","If building from partial data, look up the provider id first and merge it into the config.","Add a pre-flight check/zod schema requiring both fields so the error surfaces at the boundary."],"exampleFix":"// before\nawait manager.addModel({ modelId: 'qwen-image', /* no provider info */ } as any)\n\n// after\nawait manager.addModel({\n  providerId: 'dashscope',\n  modelId: 'qwen-image',\n} as any)","handlingStrategy":"type-guard","validationCode":"const providerId = cfg.providerId ?? cfg.provider?.id\nconst modelId = cfg.modelId ?? cfg.model?.id\nif (!providerId || !modelId) throw new Error('config lacks identity')","typeGuard":"const hasIdentity = (c: any): c is ImageModelConfigInput & { providerId: string, modelId: string } =>\n  Boolean(c?.providerId || c?.provider?.id) && Boolean(c?.modelId || c?.model?.id)","tryCatchPattern":null,"preventionTips":["Require providerId/modelId in the form/UI before submission","Validate configs with a schema before registration"],"tags":["config","validation","required-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}