Browse Source

fix: better init error messages

Adam 2 months ago
parent
commit
f949755367
2 changed files with 55 additions and 6 deletions
  1. 3 4
      packages/desktop/src/context/global-sync.tsx
  2. 52 2
      packages/desktop/src/pages/error.tsx

+ 3 - 4
packages/desktop/src/context/global-sync.tsx

@@ -15,13 +15,12 @@ import {
   type ProviderAuthResponse,
   type Command,
   createOpencodeClient,
-  EventSessionError,
 } from "@opencode-ai/sdk/v2/client"
 import { createStore, produce, reconcile } from "solid-js/store"
 import { Binary } from "@opencode-ai/util/binary"
 import { useGlobalSDK } from "./global-sdk"
-import { ErrorPage } from "../pages/error"
-import { createContext, useContext, onMount, type ParentProps, Switch, Match, createEffect } from "solid-js"
+import { ErrorPage, type InitError } from "../pages/error"
+import { createContext, useContext, onMount, type ParentProps, Switch, Match } from "solid-js"
 
 type State = {
   ready: boolean
@@ -56,7 +55,7 @@ function createGlobalSync() {
   const globalSDK = useGlobalSDK()
   const [globalStore, setGlobalStore] = createStore<{
     ready: boolean
-    error?: EventSessionError["properties"]["error"]
+    error?: InitError
     path: Path
     project: Project[]
     provider: ProviderListResponse

+ 52 - 2
packages/desktop/src/pages/error.tsx

@@ -4,12 +4,62 @@ import { Component } from "solid-js"
 import { usePlatform } from "@/context/platform"
 import { Icon } from "@opencode-ai/ui/icon"
 
+export type InitError = {
+  name: string
+  data: Record<string, unknown>
+}
+
+function formatError(error: InitError | undefined): string {
+  if (!error) return "Unknown error"
+
+  const data = error.data
+  switch (error.name) {
+    case "MCPFailed":
+      return `MCP server "${data.name}" failed. Note, opencode does not support MCP authentication yet.`
+    case "ProviderModelNotFoundError": {
+      const { providerID, modelID, suggestions } = data as {
+        providerID: string
+        modelID: string
+        suggestions?: string[]
+      }
+      return [
+        `Model not found: ${providerID}/${modelID}`,
+        ...(Array.isArray(suggestions) && suggestions.length ? ["Did you mean: " + suggestions.join(", ")] : []),
+        `Check your config (opencode.json) provider/model names`,
+      ].join("\n")
+    }
+    case "ProviderInitError":
+      return `Failed to initialize provider "${data.providerID}". Check credentials and configuration.`
+    case "ConfigJsonError":
+      return `Config file at ${data.path} is not valid JSON(C)` + (data.message ? `: ${data.message}` : "")
+    case "ConfigDirectoryTypoError":
+      return `Directory "${data.dir}" in ${data.path} is not valid. Rename the directory to "${data.suggestion}" or remove it. This is a common typo.`
+    case "ConfigFrontmatterError":
+      return `Failed to parse frontmatter in ${data.path}:\n${data.message}`
+    case "ConfigInvalidError": {
+      const issues = Array.isArray(data.issues)
+        ? data.issues.map(
+            (issue: { message: string; path: string[] }) => "↳ " + issue.message + " " + issue.path.join("."),
+          )
+        : []
+      return [`Config file at ${data.path} is invalid` + (data.message ? `: ${data.message}` : ""), ...issues].join(
+        "\n",
+      )
+    }
+    case "UnknownError":
+      return String(data.message)
+    default:
+      return data.message ? String(data.message) : JSON.stringify(data, null, 2)
+  }
+}
+
 interface ErrorPageProps {
-  error: any
+  error: InitError | undefined
 }
 
 export const ErrorPage: Component<ErrorPageProps> = (props) => {
   const platform = usePlatform()
+  console.log("ErrorPage", props.error)
   return (
     <div class="relative flex-1 h-screen w-screen min-h-0 flex flex-col items-center justify-center">
       <div class="w-2/3 max-w-3xl flex flex-col items-center justify-center gap-8">
@@ -19,7 +69,7 @@ export const ErrorPage: Component<ErrorPageProps> = (props) => {
           <p class="text-sm text-text-weak">An error occurred while loading the application.</p>
         </div>
         <TextField
-          value={String(props.error?.data?.message || props.error?.message || props.error)}
+          value={formatError(props.error)}
           readOnly
           copyable
           multiline