Summary
droid exec --model <custom-model-id> rejects all custom model IDs with "Invalid model" even though they are listed as available in the error output. Only the current session default custom model works via --model. Built-in model IDs route through Factory's API (returning 402 for non-subscribers) instead of the user's BYOK proxy.
Environment
- Droid CLI version: 0.70.0, 0.74.0 (tested both)
- OS: macOS (Darwin 23.6.0, arm64)
- Custom models: Configured in
~/.factory/settings.json with BYOK proxy at localhost
Steps to Reproduce
- Configure custom models in
~/.factory/settings.json (e.g., Gemini Flash via OpenAI-compatible proxy)
- Run:
droid exec --auto low --model "custom:Gemini-3-Flash-Low-[Proxy]-18" "Say hello"
- Observe: "Invalid model" error, even though "Gemini 3 Flash Low [Proxy]" is listed under "Available custom models"
Tested formats that all fail:
custom:Gemini-3-Flash-Low-[Proxy]-18 (the id field from settings.json)
Gemini 3 Flash Low [Proxy] (the displayName from settings.json)
custom:Claude-Haiku-4.5-Medium-Thinking-6 (non-default Claude custom model)
The only custom model that works is the one set as sessionDefaultSettings.model — which is effectively a no-op since it's already the default.
Built-in model IDs (e.g., claude-haiku-4-5-20251001) are accepted syntactically but fail with 402 Payment Required because they route through Factory's API instead of the BYOK proxy.
Expected Behavior
--model should accept any custom model ID from ~/.factory/settings.json and route through the configured BYOK endpoint, not just the current session default.
Impact
This blocks headless droid exec workflows that need to select specific models programmatically (e.g., using a cheap model for batch enrichment pipelines while keeping an expensive model as the interactive default).
Workaround
Omit the --model flag entirely and rely on the session default. This means you can't select different models for different use cases without manually changing sessionDefaultSettings.model between runs.
Log Evidence
From ~/.factory/logs/droid-log-single.log:
MetaError: Invalid model: custom:Gemini-3-Flash-Low-[Proxy]-18
at syR (src/commands/assertValidOptions.ts:83:17)
at async <anonymous> (src/commands/exec.ts:957:21)
The validation in assertValidOptions.ts lists custom models but fails to match against them.
Summary
droid exec --model <custom-model-id>rejects all custom model IDs with "Invalid model" even though they are listed as available in the error output. Only the current session default custom model works via--model. Built-in model IDs route through Factory's API (returning 402 for non-subscribers) instead of the user's BYOK proxy.Environment
~/.factory/settings.jsonwith BYOK proxy at localhostSteps to Reproduce
~/.factory/settings.json(e.g., Gemini Flash via OpenAI-compatible proxy)droid exec --auto low --model "custom:Gemini-3-Flash-Low-[Proxy]-18" "Say hello"Tested formats that all fail:
custom:Gemini-3-Flash-Low-[Proxy]-18(theidfield from settings.json)Gemini 3 Flash Low [Proxy](thedisplayNamefrom settings.json)custom:Claude-Haiku-4.5-Medium-Thinking-6(non-default Claude custom model)The only custom model that works is the one set as
sessionDefaultSettings.model— which is effectively a no-op since it's already the default.Built-in model IDs (e.g.,
claude-haiku-4-5-20251001) are accepted syntactically but fail with402 Payment Requiredbecause they route through Factory's API instead of the BYOK proxy.Expected Behavior
--modelshould accept any custom model ID from~/.factory/settings.jsonand route through the configured BYOK endpoint, not just the current session default.Impact
This blocks headless
droid execworkflows that need to select specific models programmatically (e.g., using a cheap model for batch enrichment pipelines while keeping an expensive model as the interactive default).Workaround
Omit the
--modelflag entirely and rely on the session default. This means you can't select different models for different use cases without manually changingsessionDefaultSettings.modelbetween runs.Log Evidence
From
~/.factory/logs/droid-log-single.log:The validation in
assertValidOptions.tslists custom models but fails to match against them.