{"record":{"id":"893e0e763255be90","repo":"yikart/AiToEarn","slug":"image-aspectratio-cannot-be-converted-to-a-support","errorCode":null,"errorMessage":"image aspectRatio cannot be converted to a supported size","messagePattern":"image aspectRatio cannot be converted to a supported size","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts","lineNumber":309,"sourceCode":"\n    return this.resolveScaledOpenAIImageSize(widthRatio, heightRatio, sizeProfile)\n  }\n\n  private resolveScaledOpenAIImageSize(\n    widthRatio: number,\n    heightRatio: number,\n    sizeProfile: { maxEdge: number, maxPixels: number },\n  ): string {\n    const divisor = getGreatestCommonDivisor(widthRatio, heightRatio)\n    const reducedWidth = widthRatio / divisor\n    const reducedHeight = heightRatio / divisor\n    const maxScaleByEdge = Math.floor(sizeProfile.maxEdge / Math.max(reducedWidth, reducedHeight))\n    const maxScaleByPixels = Math.floor(Math.sqrt(sizeProfile.maxPixels / (reducedWidth * reducedHeight)))\n    const maxScale = Math.min(maxScaleByEdge, maxScaleByPixels)\n    const scale = Math.floor(maxScale / OPENAI_IMAGE_SIZE_MULTIPLE) * OPENAI_IMAGE_SIZE_MULTIPLE\n\n    if (scale < OPENAI_IMAGE_SIZE_MULTIPLE) {\n      throw new BadRequestException('image aspectRatio cannot be converted to a supported size')\n    }\n\n    return `${reducedWidth * scale}x${reducedHeight * scale}`\n  }\n\n  private resolveImageExecution(\n    imageModel: string,\n    referenceImageUrls: string[],\n    aspectRatio?: string,\n    imageSize?: string,\n  ): ResolvedImageExecution {\n    this.getImageTextDraftModelConfig(imageModel)\n\n    const geminiImageModel = config.ai.models.chat.find(model =>\n      model.name === imageModel\n      && model.channel === AiLogChannel.Gemini\n      && model.outputModalities.includes('image'),\n    )","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts#L291-L327","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use a standard aspect ratio like '1:1', '3:2', '2:3' that maps to known OpenAI sizes.","Select a different imageSize/resolution profile with larger maxEdge/maxPixels.","Pick a squareSize-supporting profile for near-square ratios.","Verify OPENAI_IMAGE_SIZE_MULTIPLE and profile constants match the current OpenAI size catalog and update them if OpenAI changed sizes."],"exampleFix":"// before\nresolveOpenAIImageSize('13:7', 'low')\n// after\nresolveOpenAIImageSize('13:7', 'high') // or use a standard ratio like '2:1'","handlingStrategy":"fallback","validationCode":"// Prefer known-good combos the service can always map:\nconst safeRatios = ['1:1', '3:2', '2:3', '16:9']\nif (!safeRatios.includes(aspectRatio) && resolutionProfile === 'low') aspectRatio = '1:1'","typeGuard":"function isSafeCombo(ratio: string, profile: string): boolean {\n  const standard = ['1:1', '3:2', '2:3', '16:9']\n  return standard.includes(ratio) || profile === 'high'\n}","tryCatchPattern":"try {\n  size = resolveOpenAIImageSize(aspectRatio, profile)\n} catch (e) {\n  if (e.status === 400 && e.message.includes('cannot be converted')) {\n    size = resolveOpenAIImageSize('1:1', profile) // fallback to square\n  } else throw e\n}","preventionTips":["Stick to standard aspect ratios that map to documented OpenAI sizes.","Pair unusual ratios with a larger resolution profile.","Keep OPENAI_IMAGE_SIZE_* constants in sync with the OpenAI size catalog.","Test ratio/profile combinations in CI."],"tags":["validation","image-generation","configuration"],"backgroundTag":"image-size-unsupported","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}