JuliusBrussee/caveman · error

unsupported image token profile

Error message

unsupported image token profile

What it means

While building Gemini inline image parts, the renderer calls engineimage.EstimateTokensForModel("gemini", model, mediaResolution, w, h) per image to cost the request. If that (model, mediaResolution) combination has no token-estimation profile, estimation returns supported=false and rendering aborts: the pipeline refuses to emit images whose cost it cannot account for.

Source

Thrown at engine/pixel/transform_gemini.go:1004

		imgs, err = RenderTextToPNGsMultiCol(text, effectiveCols, effectiveNumCols)
	} else if style == (RenderStyle{}) {
		imgs, err = RenderTextToPNGs(text, effectiveCols, RenderStyle{})
	} else {
		imgs, err = RenderTextToPNGsWithCharLimit(text, effectiveCols, maxCharsPerImage, style, MaxHeightPx, "")
	}
	if err != nil {
		return geminiRenderResult{}, err
	}
	res := geminiRenderResult{droppedCodepoints: make(map[rune]int)}
	for _, img := range imgs {
		b64 := base64.StdEncoding.EncodeToString(img.PNG)
		res.parts = append(res.parts, geminiPart{InlineData: &geminiInlineData{MimeType: "image/png", Data: b64}})
		res.imageCount++
		res.imageBytes += len(img.PNG)
		res.imagePixels += img.Width * img.Height
		tokens, supported := engineimage.EstimateTokensForModel("gemini", model, mediaResolution, img.Width, img.Height)
		if !supported {
			return geminiRenderResult{}, errors.New("unsupported image token profile")
		}
		res.imageTokens += int(math.Ceil(float64(tokens) * ImageCostSafetyMargin))
		res.droppedChars += img.DroppedChars
		for cp, n := range img.DroppedCodepoints {
			res.droppedCodepoints[cp] += n
		}
	}
	return res, nil
}

func evalGeminiProfitability(model, mediaResolution, text string, cols, imageCountCap, numCols int, charsPerToken, priorWarmTokens, priorWarmImageTokens float64, shrinkWidth bool, maxCharsPerImage int, dense bool) *geminiGateEval {
	if text == "" {
		return nil
	}
	cpt := charsPerToken
	if !isFinitePositive(cpt) {
		cpt = CharsPerToken
	}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Check the model id spelling against the estimator's supported list (engineimage package)
  2. Use a known mediaResolution value for that model
  3. If the model is genuinely new, add its token profile to engineimage or fall back to text-only rendering for unsupported models

Example fix

// before
res, err := renderGeminiInlineDataParts("gemini-9-ultra", "media_hi", text, ...) // unknown model

// after
// use a model id the estimator supports, or gate image rendering:
if !engineimage.ModelSupported("gemini", model, mediaResolution) {
    // render text-only path
}
res, err := renderGeminiInlineDataParts(model, mediaResolution, text, ...)
Defensive patterns

Strategy: validation

Validate before calling

// verify the (model, mediaResolution) pair is estimable before rendering with images
if _, ok := engineimage.EstimateTokensForModel("gemini", model, mediaResolution, 1, 1); !ok {
    // use a supported model/resolution or the text-only path
}

Type guard

func imageProfileSupported(model, res string) bool {
    _, ok := engineimage.EstimateTokensForModel("gemini", model, res, 1, 1)
    return ok
}

Try / catch

res, err := renderGeminiInlineDataParts(model, res0, ...)
if err != nil && strings.Contains(err.Error(), "unsupported image token profile") {
    // fall back to text-only rendering
}

Prevention

When it happens

Trigger: Passing a model string the estimator does not recognize (new, renamed, or misspelled Gemini model id), or a mediaResolution value outside the known set, together with a render that actually produces at least one image.

Common situations: Upgrading to a newly released Gemini model before the estimator table knows it; typo'd model name from config; passing an empty model that falls back to an unrecognized default; unusual media_resolution enum values from client config.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/86f9136e90a14f8b. Report an issue: GitHub.