yikart/AiToEarn · error · AppException

InvalidModel

InvalidModel

Error message

InvalidModel

What it means

userGeminiGeneration resolves the requested Gemini image model (defaulting to 'gemini-3.1-flash-image-preview') against the configured Gemini image model registry via getGeminiImageModelConfig. If no config exists for that model name it throws AppException(ResponseCode.InvalidModel), meaning the model is unknown/not enabled in this deployment, not that the upstream call failed.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/image/image.service.ts:249

      images.push({ url: uploadResult.asset.path, data: image.imageData.toString('base64'), mimeType: image.mimeType })
    }

    return {
      images,
      usage: result.usage,
    }
  }

  /**
   * 用户 Gemini 图片生成
   */
  async userGeminiGeneration(request: UserGeminiImageGenerationDto) {
    const { userId, userType, model: requestedModel, ...params } = request
    const model = requestedModel || 'gemini-3.1-flash-image-preview'

    const modelConfig = await this.getGeminiImageModelConfig(model)
    if (!modelConfig) {
      throw new AppException(ResponseCode.InvalidModel)
    }

    const startedAt = new Date()
    const result = await this.geminiGeneration(userId, { ...params, model })

    const usage = result.usage || { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 }

    const duration = Date.now() - startedAt.getTime()

    await this.aiLogRepo.create({
      userId,
      userType,
      model,
      channel: AiLogChannel.Gemini,
      type: AiLogType.Image,
      request: params,
      response: { ...result, data: void 0 },
      status: AiLogStatus.Success,

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Check the requested model against the list returned by getGeminiImageModelConfig / the configured model registry
  2. Correct the model name (spelling, exact id including preview suffix)
  3. Add the model to the Gemini image model config if it should be supported in this environment
  4. Omit model to fall back to the default 'gemini-3.1-flash-image-preview'

Example fix

// before
const modelConfig = await imageService.getGeminiImageModelConfig(model)
// after
if (!(await imageService.getGeminiImageModelConfig(model))) {
  const available = await imageService.getGeminiImageModels()
  throw new BadRequestException(`Unknown model ${model}, available: ${available.map(m => m.name).join(',')}`)
}
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = ['gemini-3.1-flash-image-preview' /* fetch full list from model config */]
if (model && !SUPPORTED.includes(model)) throw new BadRequestException(`Unsupported Gemini image model: ${model}`)

Type guard

function isValidModel(m: string | undefined): m is string {
  return typeof m === 'string' && m.length > 0 // then check membership against configured list
}

Try / catch

try {
  await imageService.userGeminiGeneration(dto)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.InvalidModel) {
    throw new BadRequestException(`Model ${dto.model} is not available; omit 'model' to use the default`)`
  }
  throw e
}

Prevention

When it happens

Trigger: Client requests a model name that is not present in the Gemini image model config (typo, deprecated name, or a model only available in another environment), or the default model 'gemini-3.1-flash-image-preview' is not registered in the deployment's config.

Common situations: Model renamed/rotated by Google and config not updated; passing a chat model name (e.g. 'gemini-2.0-flash') to the image endpoint; staging environment missing model entries that production has.

Related errors


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