diff --git a/packages/opencode/src/server/routes/instance/httpapi/middleware/proxy.ts b/packages/opencode/src/server/routes/instance/httpapi/middleware/proxy.ts index e5362f8cbe13..d21ab5647c1e 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/middleware/proxy.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/middleware/proxy.ts @@ -97,6 +97,29 @@ export function http( headers.delete("content-encoding") headers.delete("content-length") + // An upstream 5xx from a remote workspace sandbox arrives here as an opaque + // status — its real cause (and log line) live only inside the sandbox. Buffer + // the small error body, log it locally so it shows up in the host's log, and + // forward it unchanged (preserving content-type so the client can still parse + // the structured error, e.g. its `ref`). + if (response.status >= 500) { + const body = yield* response.text.pipe(Effect.catch(() => Effect.succeed(""))) + const contentType = response.headers["content-type"] ?? "application/json" + headers.delete("content-type") + yield* Effect.logError("workspace proxy upstream error", { + url: url.toString(), + method: request.method, + status: response.status, + body: body.slice(0, 2000), + }) + return HttpServerResponse.text(body, { + status: response.status, + statusText: statusText(response), + headers, + contentType, + }) + } + return HttpServerResponse.stream(response.stream.pipe(Stream.catchCause(() => Stream.empty)), { status: response.status, statusText: statusText(response),