yikart/AiToEarn · error · BadRequestException

image aspectRatio cannot be converted to a supported size

Error message

image aspectRatio cannot be converted to a supported size

What it means

resolveScaledOpenAIImageSize scales a reduced (coprime) ratio up to an OpenAI size that fits sizeProfile.maxEdge and maxPixels while remaining a multiple of OPENAI_IMAGE_SIZE_MULTIPLE. When even one multiple-step scale does not fit within the pixel/edge budget, it throws this BadRequestException.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts:309

    return this.resolveScaledOpenAIImageSize(widthRatio, heightRatio, sizeProfile)
  }

  private resolveScaledOpenAIImageSize(
    widthRatio: number,
    heightRatio: number,
    sizeProfile: { maxEdge: number, maxPixels: number },
  ): string {
    const divisor = getGreatestCommonDivisor(widthRatio, heightRatio)
    const reducedWidth = widthRatio / divisor
    const reducedHeight = heightRatio / divisor
    const maxScaleByEdge = Math.floor(sizeProfile.maxEdge / Math.max(reducedWidth, reducedHeight))
    const maxScaleByPixels = Math.floor(Math.sqrt(sizeProfile.maxPixels / (reducedWidth * reducedHeight)))
    const maxScale = Math.min(maxScaleByEdge, maxScaleByPixels)
    const scale = Math.floor(maxScale / OPENAI_IMAGE_SIZE_MULTIPLE) * OPENAI_IMAGE_SIZE_MULTIPLE

    if (scale < OPENAI_IMAGE_SIZE_MULTIPLE) {
      throw new BadRequestException('image aspectRatio cannot be converted to a supported size')
    }

    return `${reducedWidth * scale}x${reducedHeight * scale}`
  }

  private resolveImageExecution(
    imageModel: string,
    referenceImageUrls: string[],
    aspectRatio?: string,
    imageSize?: string,
  ): ResolvedImageExecution {
    this.getImageTextDraftModelConfig(imageModel)

    const geminiImageModel = config.ai.models.chat.find(model =>
      model.name === imageModel
      && model.channel === AiLogChannel.Gemini
      && model.outputModalities.includes('image'),
    )

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Use a standard aspect ratio like '1:1', '3:2', '2:3' that maps to known OpenAI sizes.
  2. Select a different imageSize/resolution profile with larger maxEdge/maxPixels.
  3. Pick a squareSize-supporting profile for near-square ratios.
  4. Verify OPENAI_IMAGE_SIZE_MULTIPLE and profile constants match the current OpenAI size catalog and update them if OpenAI changed sizes.

Example fix

// before
resolveOpenAIImageSize('13:7', 'low')
// after
resolveOpenAIImageSize('13:7', 'high') // or use a standard ratio like '2:1'
Defensive patterns

Strategy: fallback

Validate before calling

// Prefer known-good combos the service can always map:
const safeRatios = ['1:1', '3:2', '2:3', '16:9']
if (!safeRatios.includes(aspectRatio) && resolutionProfile === 'low') aspectRatio = '1:1'

Type guard

function isSafeCombo(ratio: string, profile: string): boolean {
  const standard = ['1:1', '3:2', '2:3', '16:9']
  return standard.includes(ratio) || profile === 'high'
}

Try / catch

try {
  size = resolveOpenAIImageSize(aspectRatio, profile)
} catch (e) {
  if (e.status === 400 && e.message.includes('cannot be converted')) {
    size = resolveOpenAIImageSize('1:1', profile) // fallback to square
  } else throw e
}

Prevention

When it happens

Trigger: A valid in-range ratio whose reduced dimensions cannot be scaled to any allowed size for the chosen imageSize profile — floor(maxScale / MULTIPLE) * MULTIPLE < MULTIPLE, e.g. an unusual ratio combined with a small resolution profile.

Common situations: Combining an unusual aspect ratio (e.g. 13:8) with a low resolution profile that has no matching size; custom imageSize values not in the known profiles; OpenAI changing its allowed size catalog so the profiles no longer map.

Related errors


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