fix(sdk): wrap thrown error bodies in Error

SDK throwOnError paths now convert structured response bodies into real Error instances while preserving the original body and status in cause.
This commit is contained in:
Kit Langton
2026-05-09 18:46:43 -04:00
committed by GitHub
parent 864fab86a9
commit faed9230dd
5 changed files with 138 additions and 20 deletions
+2 -19
View File
@@ -3,6 +3,7 @@ export * from "./gen/types.gen.js"
import { createClient } from "./gen/client/client.gen.js"
import { type Config } from "./gen/client/types.gen.js"
import { OpencodeClient } from "./gen/sdk.gen.js"
import { wrapClientError } from "../error-interceptor.js"
export { type Config as OpencodeClientConfig, OpencodeClient }
function pick(value: string | null, fallback?: string, encode?: (value: string) => string) {
@@ -84,24 +85,6 @@ export function createOpencodeClient(config?: Config & { directory?: string; exp
return response
})
// The generated client falls back to throwing a literal `{}` when the server
// responds with an empty / unparseable error body, which surfaces as a bare
// `{}` in TUI / CLI error output. Wrap ONLY that case in a real Error so
// downstream formatters get a useful message — but pass through any parsed
// JSON error body unchanged so existing consumers can still inspect fields.
client.interceptors.error.use((error, response, request) => {
const isEmpty =
error === undefined ||
error === null ||
error === "" ||
(typeof error === "object" && !(error instanceof Error) && Object.keys(error).length === 0)
if (!isEmpty) return error
const method = request?.method ?? "?"
const url = request?.url ?? "?"
if (!response) return new Error(`opencode server ${method} ${url}: network error (no response)`)
const status = response.status
const statusText = response.statusText ? " " + response.statusText : ""
return new Error(`opencode server ${method} ${url}${status}${statusText}: (empty response body)`)
})
client.interceptors.error.use(wrapClientError)
return new OpencodeClient({ client })
}