{"record":{"id":"0f18da8af96039dc","repo":"paperclipai/paperclip","slug":"opencode-runtime-request-is-not-resolvable","errorCode":null,"errorMessage":"OpenCode runtime request is not resolvable","messagePattern":"OpenCode runtime request is not resolvable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/cli/opencode-app-server-proxy.ts","lineNumber":251,"sourceCode":"    } else if (event.eventType === \"run.result.proposed\") {\n      send({\n        method: \"paperclip/runResult\",\n        params: {\n          threadId: opened.ids().driverSessionId,\n          turnId: event.turnId,\n          itemId: event.itemId ?? \"semantic-result\",\n          result: payload,\n        },\n      });\n    } else if (event.eventType === \"runtime_request.created\") {\n      const request = record(payload.request);\n      const requestId = text(request.requestId);\n      const turnId = text(\n        request.turnId,\n        text(event.turnId, activeTurnId ?? \"\"),\n      );\n      if (!requestId || !turnId || !opened.resolveRuntimeRequest) {\n        throw new Error(\"OpenCode runtime request is not resolvable\");\n      }\n      // Keep consuming OpenCode SSE while the controller waits for the user.\n      // If the underlying provider disappears, the stream can then fail the\n      // proxy and runnerd will expire the still-pending canonical request.\n      void (async () => {\n        const controllerResponse = record(\n          await requestController(\"paperclip/runtimeRequest\", {\n            request,\n          }),\n        );\n        await opened.resolveRuntimeRequest!({\n          requestId,\n          turnId,\n          resolution: record(\n            controllerResponse.resolution,\n          ) as HarnessRuntimeRequestResolution,\n        });\n      })().catch((error) => failProxy(error));","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/cli/opencode-app-server-proxy.ts#L233-L269","documentation":"When an OpenCode event carries a runtime user request (e.g. an interactive prompt), the proxy must map it to a canonical pending request: it needs a requestId, a turnId (from the request, event, or active turn), and a resolveRuntimeRequest callback registered at open time. If any is missing, the proxy throws because it cannot correlate the runtime request.","triggerScenarios":"pumpEvents encounters a request event where requestId is empty, both request.turnId and event.turnId are empty and activeTurnId is null, or the session was opened without a resolveRuntimeRequest callback.","commonSituations":"A permission/user-input prompt arrives after the proxy lost track of the active turn; opening the proxy without wiring the runtime-request resolver; provider events arriving out of order before the first turn was registered.","solutions":["Ensure open() is called with a resolveRuntimeRequest callback wired to the canonical request store","Guarantee request events include requestId and turnId (or that an active turn exists before prompts fire)","Fix upstream event ordering so turn start is processed before request events"],"exampleFix":"// before\nconst opened = await openProxy(params); // no resolver\n// after\nconst opened = await openProxy({ ...params, resolveRuntimeRequest: canonicalStore.resolve });","handlingStrategy":"type-guard","validationCode":"function canResolveRuntimeRequest(ev, activeTurnId, opened) { return Boolean(String(ev.requestId ?? '')) && Boolean(String(ev.turnId ?? activeTurnId ?? '')) && typeof opened.resolveRuntimeRequest === 'function'; }","typeGuard":"function isResolvableRuntimeRequest(r: { requestId?: string; turnId?: string }, activeTurnId: string | null, opened: { resolveRuntimeRequest?: unknown }): boolean {\n  return Boolean(r.requestId) && Boolean(r.turnId ?? activeTurnId) && typeof opened.resolveRuntimeRequest === 'function';\n}","tryCatchPattern":"try { await pumpEvents(opened); }\ncatch (e) { if (String(e.message).includes('not resolvable')) { failPendingCanonicalRequests(opened, e); } else throw e; }","preventionTips":["Always wire resolveRuntimeRequest when opening the proxy","Ensure provider request events carry requestId and turnId; fail the canonical request otherwise so callers are not left pending","Keep an activeTurnId registered for the duration of interactive turns"],"tags":["opencode","events","request-correlation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}