summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIan Maurer <[email protected]>2025-11-21 03:01:19 -0500
committerGitHub <[email protected]>2025-11-21 02:01:19 -0600
commite018e16898adb241c4ca9f18f1b54034f36c2dea (patch)
tree28d524f5cde51d136d1cbfd929c56bbf0dcb3bca
parentd16c8c9f0fda4bdd3b41c3cf9fca84daa3262e9a (diff)
downloadopencode-e018e16898adb241c4ca9f18f1b54034f36c2dea.tar.gz
opencode-e018e16898adb241c4ca9f18f1b54034f36c2dea.zip
fix(cli): ensure clean exit on provider/model errors (#4223)
Co-authored-by: GitHub Action <[email protected]> Co-authored-by: Aiden Cline <[email protected]>
-rw-r--r--packages/opencode/src/cli/error.ts13
-rw-r--r--packages/opencode/src/provider/provider.ts18
2 files changed, 29 insertions, 2 deletions
diff --git a/packages/opencode/src/cli/error.ts b/packages/opencode/src/cli/error.ts
index 464afc710..77f4cec6b 100644
--- a/packages/opencode/src/cli/error.ts
+++ b/packages/opencode/src/cli/error.ts
@@ -1,11 +1,24 @@
import { ConfigMarkdown } from "@/config/markdown"
import { Config } from "../config/config"
import { MCP } from "../mcp"
+import { Provider } from "../provider/provider"
import { UI } from "./ui"
export function FormatError(input: unknown) {
if (MCP.Failed.isInstance(input))
return `MCP server "${input.data.name}" failed. Note, opencode does not support MCP authentication yet.`
+ if (Provider.ModelNotFoundError.isInstance(input)) {
+ const { providerID, modelID, suggestions } = input.data
+ return [
+ `Model not found: ${providerID}/${modelID}`,
+ ...(Array.isArray(suggestions) && suggestions.length ? ["Did you mean: " + suggestions.join(", ")] : []),
+ `Try: \`opencode models\` to list available models`,
+ `Or check your config (opencode.json) provider/model names`,
+ ].join("\n")
+ }
+ if (Provider.InitError.isInstance(input)) {
+ return `Failed to initialize provider "${input.data.providerID}". Check credentials and configuration.`
+ }
if (Config.JsonError.isInstance(input)) {
return (
`Config file at ${input.data.path} is not valid JSON(C)` + (input.data.message ? `: ${input.data.message}` : "")
diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts
index 7fbc1b88c..038ccc072 100644
--- a/packages/opencode/src/provider/provider.ts
+++ b/packages/opencode/src/provider/provider.ts
@@ -1,4 +1,5 @@
import z from "zod"
+import fuzzysort from "fuzzysort"
import { Config } from "../config/config"
import { mergeDeep, sortBy } from "remeda"
import { NoSuchModelError, type LanguageModel, type Provider as SDK } from "ai"
@@ -597,9 +598,21 @@ export namespace Provider {
})
const provider = s.providers[providerID]
- if (!provider) throw new ModelNotFoundError({ providerID, modelID })
+ if (!provider) {
+ const availableProviders = Object.keys(s.providers)
+ const matches = fuzzysort.go(providerID, availableProviders, { limit: 3, threshold: -10000 })
+ const suggestions = matches.map((m) => m.target)
+ throw new ModelNotFoundError({ providerID, modelID, suggestions })
+ }
+
const info = provider.info.models[modelID]
- if (!info) throw new ModelNotFoundError({ providerID, modelID })
+ if (!info) {
+ const availableModels = Object.keys(provider.info.models)
+ const matches = fuzzysort.go(modelID, availableModels, { limit: 3, threshold: -10000 })
+ const suggestions = matches.map((m) => m.target)
+ throw new ModelNotFoundError({ providerID, modelID, suggestions })
+ }
+
const sdk = await getSDK(provider.info, info)
try {
@@ -700,6 +713,7 @@ export namespace Provider {
z.object({
providerID: z.string(),
modelID: z.string(),
+ suggestions: z.array(z.string()).optional(),
}),
)