I have google-free (free Gemini API) configured as the primary model for both image analysis and audio transcription, with the paid google provider as a fallback. Despite the config being correct and the free API key working when tested directly, the paid model is sometimes used. There's no way to trace why.
Config
Image analysis:
{
"primary": "google-free/gemini-3.1-flash-lite",
"fallbacks": ["google/gemini-3.1-flash-lite"]
}
Audio transcription:
[
{ "provider": "google-free", "model": "gemini-3.1-flash-lite" },
{ "provider": "google", "model": "gemini-3.1-flash-lite" }
]
Both google and google-free providers have their own separate API keys configured. The free key is functional — tested it directly against Google's API and it returned valid results.
What I've checked
- Config is correct per openclaw.json and config.get
- Both API keys are present and different from each other
- Free key works — sent a test image directly, got a valid response
- Searched trajectory logs for the model used by the image tool — found nothing. Trajectory logs don't record which model was selected for media processing, only the main text model
The problem
The image tool uses runWithImageModelFallback(), which builds a candidate list from primary → fallbacks[] and tries each in order. On any error (HTTP 429, timeout, empty response, etc.) it moves to the next candidate silently. When the paid model ends up being used, I can see it on the billing side but can't tell what caused the fallback — there's nothing in the logs to work from.
Looking for guidance on:
• How to add visibility into which model actually processed a given image/audio request
• Whether there are known issues with the free Gemini API key's per-minute/per-day quotas triggering fallback
• Any config changes that could help reduce the frequency of fallback to the paid tier