{"record":{"id":"9338f72cfce77401","repo":"yikart/AiToEarn","slug":"invalidmodel-9338f7","errorCode":"InvalidModel","errorMessage":"ResponseCode.InvalidModel","messagePattern":"ResponseCode\\.InvalidModel","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/video.service.ts","lineNumber":52,"sourceCode":"\n  constructor(\n    private readonly userRepo: UserRepository,\n    private readonly aiLogRepo: AiLogRepository,\n    private readonly modelsConfigService: ModelsConfigService,\n    private readonly assetsService: AssetsService,\n    private readonly videoMetadataService: VideoMetadataService,\n    private readonly materialGroupRepository: MaterialGroupRepository,\n    private readonly mediaRepository: MediaRepository,\n    private readonly volcengineVideoService: VolcengineVideoService,\n    private readonly openaiVideoService: OpenAIVideoService,\n    private readonly grokVideoService: GrokVideoService,\n    private readonly dashscopeVideoService: DashscopeVideoService,\n    @Optional() private readonly relayVideoService?: RelayVideoService,\n  ) {}\n\n  private requireChannel<T>(service: T | undefined): T {\n    if (!service) {\n      throw new AppException(ResponseCode.InvalidModel)\n    }\n    return service\n  }\n\n  /**\n   * 用户视频生成（通用接口）\n   */\n  async userVideoGeneration(request: UserVideoGenerationRequestDto) {\n    const { model, groupId, userId } = request\n\n    if (groupId) {\n      const group = await this.materialGroupRepository.getInfo(groupId)\n      if (!group || group.userId !== userId) {\n        throw new AppException(ResponseCode.MaterialGroupNotFound)\n      }\n    }\n\n    const modelConfig = this.modelsConfigService.config.video.generation.find(m => m.name === model)","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/video.service.ts#L34-L70","documentation":"InvalidModel thrown by VideoService.requireChannel when the channel-specific video service (e.g. relayVideoService) is not available/injected. The generic video facade requires the target channel's service to be registered; if the optional dependency is undefined, the requested model's channel cannot be served.","triggerScenarios":"userVideoGeneration, extractInput, or getChannelTaskResult resolve the channel service via requireChannel(service) and the service is undefined — e.g. RelayVideoService is @Optional() and not provided because the Relay module/config is disabled or missing.","commonSituations":"Relay feature flag/env var not enabled in this deployment; module not imported so the provider isn't registered; requesting a model whose channel maps to a service that isn't configured; DI misconfiguration after refactoring.","solutions":["Enable/register the missing channel service (import the Relay video module or set the enabling env/config)","Pick a model whose channel service is available in this deployment","Check that @Optional() RelayVideoService is actually provided in the module providers list","Verify models config doesn't advertise channels the deployment can't serve"],"exampleFix":"// before (module)\nproviders: [VideoService] // RelayVideoService missing\n// after\nproviders: [VideoService, RelayVideoService]\n// or guard the caller\nconst service = channel === 'relay' ? relayVideoService : dashscopeVideoService\nif (!service) throw new AppException(ResponseCode.InvalidModel)","handlingStrategy":"validation","validationCode":"const service = channel === 'relay' ? relayVideoService : dashscopeVideoService\nif (!service) {\n  throw new Error(`Channel service unavailable for model ${model}; enable/register the channel module`)\n}","typeGuard":"function channelAvailable<T>(s: T | undefined | null): s is T {\n  return s !== undefined && s !== null\n}","tryCatchPattern":"try {\n  await videoService.userVideoGeneration(req)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.InvalidModel) {\n    // fall back to a model whose channel is registered, or surface 'channel not enabled in this deployment'\n  } else throw e\n}","preventionTips":["Register all needed channel providers in the module (RelayVideoService is @Optional())","Gate advertised models on enabled channel config","Add a startup check that every configured model's channel service is resolvable","Document which channels each deployment enables via env/flags"],"tags":["invalid-model","dependency-injection","channel","config"],"backgroundTag":"channel-service-unavailable","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}