From 0e14404e5f15303ab0b4165397198530a70528bc Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Fri, 22 May 2026 23:15:53 +0530 Subject: [PATCH] fix(sync): map workspace warp not found (#28882) --- .../instance/httpapi/groups/workspace.ts | 3 ++- .../instance/httpapi/handlers/workspace.ts | 2 ++ .../test/server/httpapi-workspace.test.ts | 21 +++++++++++++++++++ packages/sdk/js/src/v2/gen/types.gen.ts | 4 ++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/workspace.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/workspace.ts index 1c40ae3cb8..6a5101dc42 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/workspace.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/workspace.ts @@ -3,6 +3,7 @@ import { WorkspaceAdapterEntry } from "@/control-plane/types" import { Schema, Struct } from "effect" import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" import { ApiVcsApplyError } from "./instance" +import { ApiNotFoundError } from "../errors" import { Authorization } from "../middleware/authorization" import { InstanceContextMiddleware } from "../middleware/instance-context" import { WorkspaceRoutingMiddleware, WorkspaceRoutingQuery } from "../middleware/workspace-routing" @@ -107,7 +108,7 @@ export const WorkspaceApi = HttpApi.make("workspace") query: WorkspaceRoutingQuery, payload: WarpPayload, success: described(HttpApiSchema.NoContent, "Session warped"), - error: [ApiWorkspaceWarpError, ApiVcsApplyError], + error: [ApiWorkspaceWarpError, ApiVcsApplyError, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "experimental.workspace.warp", diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/workspace.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/workspace.ts index c22b82ddeb..2699c86590 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/workspace.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/workspace.ts @@ -5,6 +5,7 @@ import { Vcs } from "@/project/vcs" import { Effect } from "effect" import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi" import { InstanceHttpApi } from "../api" +import { notFound } from "../errors" import { ApiVcsApplyError } from "../groups/instance" import { ApiWorkspaceWarpError, CreatePayload, WarpPayload } from "../groups/workspace" @@ -54,6 +55,7 @@ export const workspaceHandlers = HttpApiBuilder.group(InstanceHttpApi, "workspac }) .pipe( Effect.mapError((error) => { + if (error instanceof Workspace.WorkspaceNotFoundError) return notFound(error.message) if (error instanceof Vcs.PatchApplyError) { return new ApiVcsApplyError({ name: "VcsApplyError", diff --git a/packages/opencode/test/server/httpapi-workspace.test.ts b/packages/opencode/test/server/httpapi-workspace.test.ts index a3cca6e475..2e10d325f6 100644 --- a/packages/opencode/test/server/httpapi-workspace.test.ts +++ b/packages/opencode/test/server/httpapi-workspace.test.ts @@ -5,6 +5,7 @@ import path from "node:path" import { Effect, Layer } from "effect" import { Flag } from "@opencode-ai/core/flag/flag" import { registerAdapter } from "../../src/control-plane/adapters" +import { WorkspaceID } from "../../src/control-plane/schema" import type { WorkspaceAdapter } from "../../src/control-plane/types" import { Workspace } from "../../src/control-plane/workspace" import { WorkspacePaths } from "../../src/server/routes/instance/httpapi/groups/workspace" @@ -250,6 +251,26 @@ describe("workspace HttpApi", () => { }), ) + it.live("returns a declared not found error when warping into a missing workspace", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + const session = yield* Session.use.create({}).pipe(provideInstance(dir)) + const workspaceID = WorkspaceID.ascending("wrk_missing_warp") + + const response = yield* request(WorkspacePaths.warp, dir, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ id: workspaceID, sessionID: session.id }), + }) + + expect(response.status).toBe(404) + expect(yield* Effect.promise(() => response.json())).toEqual({ + name: "NotFoundError", + data: { message: `Workspace not found: ${workspaceID}` }, + }) + }), + ) + it.live("creates workspace with the TUI payload shape", () => Effect.gen(function* () { Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 15f4f7cb74..ca9eaab71d 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -8169,6 +8169,10 @@ export type ExperimentalWorkspaceWarpErrors = { * WorkspaceWarpError | VcsApplyError | InvalidRequestError */ 400: WorkspaceWarpError | VcsApplyError | InvalidRequestError + /** + * NotFoundError + */ + 404: NotFoundError } export type ExperimentalWorkspaceWarpError = ExperimentalWorkspaceWarpErrors[keyof ExperimentalWorkspaceWarpErrors]