yikart/AiToEarn · error · AppException

InvalidModel

InvalidModel

Error message

InvalidModel

What it means

getModelConfig looks up the requested video model name in modelsConfigService.config.video.generation. If no configuration entry matches the requested model name, it throws AppException(ResponseCode.InvalidModel), meaning the model is unknown to this deployment.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/dashscope/dashscope.service.ts:61

@Injectable()
export class DashscopeVideoService {
  private readonly logger = new Logger(DashscopeVideoService.name)

  constructor(
    private readonly dashscopeLibService: DashscopeLibService,
    private readonly aiLogRepo: AiLogRepository,
    private readonly assetsService: AssetsService,
    private readonly storageProvider: StorageProvider,
    private readonly modelsConfigService: ModelsConfigService,
    private readonly videoMetadataService: VideoMetadataService,
    private readonly aiAvailability: AiAvailabilityService,
  ) {}

  private getModelConfig(model: string): DashscopeModelConfig {
    const modelConfig = this.modelsConfigService.config.video.generation.find(m => m.name === model)
    if (!modelConfig) {
      throw new AppException(ResponseCode.InvalidModel)
    }
    return modelConfig as DashscopeModelConfig
  }

  private getProviderModel(modelConfig: DashscopeModelConfig, mode: string, resolution: string | undefined): string {
    const runtimeModel = modelConfig.runtimeModels
      ?.filter(item => (item.mode == null || item.mode === mode) && (item.resolution == null || item.resolution === resolution))
      .sort((a, b) => Number(b.mode != null) + Number(b.resolution != null) - Number(a.mode != null) - Number(a.resolution != null))[0]
    if (!runtimeModel) {
      throw new AppException(ResponseCode.InvalidModel)
    }
    return runtimeModel.model
  }

  private async toAccessibleUrl(url: string): Promise<string> {
    const parsed = this.storageProvider.parsePathFromUrl(url)
    if (parsed.startsWith('http')) {
      return url

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Log/print the requested model and compare with modelsConfigService.config.video.generation names for exact (case-sensitive) match.
  2. Add the model entry to the video.generation configuration for this environment.
  3. Fix the client to send one of the supported model names.
  4. Restart/reload the config service if the model was recently added.

Example fix

// before
generateVideo({ model: 'wan2.1-t2v-plus', ... })
// after
generateVideo({ model: 'wan2.1-t2v-plus-v2', ... }) // name present in video.generation config
Defensive patterns

Strategy: validation

Validate before calling

const supported = modelsConfigService.config.video.generation.map(m => m.name)
if (!supported.includes(model)) {
  throw new Error(`Unsupported model '${model}'. Supported: ${supported.join(', ')}`)
}

Type guard

function isKnownModel(model: string, configs: { name: string }[]): boolean {
  return configs.some(c => c.name === model)
}

Try / catch

try {
  await videoService.generate({ model, ... })
} catch (err) {
  if (err.code === 'InvalidModel') {
    // fall back to a default known-good model or show supported models to the user
  }
}

Prevention

When it happens

Trigger: A video generation request supplies a model string that does not exactly match any name in the video.generation models config (case-sensitive, exact match).

Common situations: Typo in model name; config file missing the model for this environment; client using a DashScope model name the backend has not whitelisted; config hot-reload not applied after adding a model.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/436e5b373b9d4ccf. Report an issue: GitHub.