plandex-ai/plandex · error
'%s' is a local-only built-in model, so it can't be used on
Error message
'%s' is a local-only built-in model, so it can't be used on Plandex Cloud
What it means
A 422 validation error thrown when running on Plandex Cloud (IS_CLOUD set) and a custom model pack references a built-in base model for which bm.IsLocalOnly() is true. Local-only built-in models depend on locally running inference and are banned from cloud model pack configurations.
Source
Thrown at app/server/handlers/models.go:248
// ensure that all models are either built-in, being imported, or already exist
allModelIds := modelPack.AllModelIds()
for _, modelId := range allModelIds {
_, exists := existingCustomModelIds[modelId]
_, creating := inputModelIds[string(modelId)]
bm, builtIn := shared.BuiltInBaseModelsById[modelId]
if !exists && !creating && !builtIn {
msg := fmt.Sprintf("'%s' is not built-in, not being imported, and not an existing custom model", modelId)
log.Println(msg)
http.Error(w, msg, http.StatusUnprocessableEntity)
return
}
if builtIn && os.Getenv("IS_CLOUD") != "" && bm.IsLocalOnly() {
msg := fmt.Sprintf("'%s' is a local-only built-in model, so it can't be used on Plandex Cloud", modelId)
log.Println(msg)
http.Error(w, msg, http.StatusUnprocessableEntity)
return
}
}
mp := modelPack.ToModelPack()
dbMp := db.ModelPackFromApi(&mp)
dbMp.OrgId = auth.OrgId
dbMp.Id = mp.Id
toUpsertModelPacks = append(toUpsertModelPacks, dbMp)
}
toDeleteCustomModelIds := []string{}
toDeleteCustomProviderIds := []string{}
toDeleteModelPackIds := []string{}
for _, model := range customModels {
if _, exists := inputModelIds[string(model.ModelId)]; !exists {View on GitHub (pinned to e2d772072e)
Solutions
- Replace local-only built-in model ids in the pack with cloud-compatible built-ins
- Remove those model entries from the pack before importing on cloud
- Use self-hosted Plandex if local-only models are required in packs
- Maintain environment-specific pack definitions
Example fix
// before (on Plandex Cloud)
{"name": "my-pack", "summarizer": {"modelId": "ollama-local-model"}}
// after (on Plandex Cloud)
{"name": "my-pack", "summarizer": {"modelId": "claude-3-haiku"}} Defensive patterns
Strategy: validation
Validate before calling
// pre-check local-only built-ins in packs when on cloud
if isCloud {
for _, pack := range in.CustomModelPacks {
for _, id := range pack.AllModelIds() {
if bm, ok := shared.BuiltInBaseModelsById[id]; ok && bm.IsLocalOnly() {
return fmt.Errorf("pack references local-only built-in model: %q", id)
}
}
}
} Type guard
func cloudCompatibleModel(id shared.ModelId) bool {
bm, builtIn := shared.BuiltInBaseModelsById[id]
return !builtIn || !bm.IsLocalOnly()
} Try / catch
// deterministic 422 — swap local-only models then resubmit once
if resp.StatusCode == 422 && strings.Contains(bodyText, "local-only built-in model") {
input = replaceLocalOnlyModels(input)
return upsert(input)
} Prevention
- Audit pack model ids for IsLocalOnly() before cloud imports
- Keep cloud and local pack definitions separate
- Check every role in the pack, not just the planner
- Prefer explicit cloud-safe model ids in shared team configs
When it happens
Trigger: POST to the upsert custom models endpoint against Plandex Cloud with a CustomModelPacks entry whose AllModelIds() includes a local-only built-in base model id (e.g. a locally hosted ollama model that ships as a built-in).
Common situations: Copying a self-hosted model pack config to cloud; shared team config files that mix local and cloud environments; forgetting that the restriction applies to any role in the pack, not just the planner.
Related errors
- '%s' is a local-only model provider, so it can't be used on
- '%s' is not a custom model provider that exists or is being
- '%s' is not a built-in model provider
- '%s' is not built-in, not being imported, and not an existin
- invalid context index: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/886a3ba4be88da73.
Report an issue: GitHub.