paperclipai/paperclip · error

OpenCode runtime request is not resolvable

Error message

OpenCode runtime request is not resolvable

What it means

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.

Source

Thrown at packages/paperclip-runner/src/cli/opencode-app-server-proxy.ts:251

    } else if (event.eventType === "run.result.proposed") {
      send({
        method: "paperclip/runResult",
        params: {
          threadId: opened.ids().driverSessionId,
          turnId: event.turnId,
          itemId: event.itemId ?? "semantic-result",
          result: payload,
        },
      });
    } else if (event.eventType === "runtime_request.created") {
      const request = record(payload.request);
      const requestId = text(request.requestId);
      const turnId = text(
        request.turnId,
        text(event.turnId, activeTurnId ?? ""),
      );
      if (!requestId || !turnId || !opened.resolveRuntimeRequest) {
        throw new Error("OpenCode runtime request is not resolvable");
      }
      // Keep consuming OpenCode SSE while the controller waits for the user.
      // If the underlying provider disappears, the stream can then fail the
      // proxy and runnerd will expire the still-pending canonical request.
      void (async () => {
        const controllerResponse = record(
          await requestController("paperclip/runtimeRequest", {
            request,
          }),
        );
        await opened.resolveRuntimeRequest!({
          requestId,
          turnId,
          resolution: record(
            controllerResponse.resolution,
          ) as HarnessRuntimeRequestResolution,
        });
      })().catch((error) => failProxy(error));

View on GitHub (pinned to 01ad858492)

Solutions

  1. Ensure open() is called with a resolveRuntimeRequest callback wired to the canonical request store
  2. Guarantee request events include requestId and turnId (or that an active turn exists before prompts fire)
  3. Fix upstream event ordering so turn start is processed before request events

Example fix

// before
const opened = await openProxy(params); // no resolver
// after
const opened = await openProxy({ ...params, resolveRuntimeRequest: canonicalStore.resolve });
Defensive patterns

Strategy: type-guard

Validate before calling

function canResolveRuntimeRequest(ev, activeTurnId, opened) { return Boolean(String(ev.requestId ?? '')) && Boolean(String(ev.turnId ?? activeTurnId ?? '')) && typeof opened.resolveRuntimeRequest === 'function'; }

Type guard

function isResolvableRuntimeRequest(r: { requestId?: string; turnId?: string }, activeTurnId: string | null, opened: { resolveRuntimeRequest?: unknown }): boolean {
  return Boolean(r.requestId) && Boolean(r.turnId ?? activeTurnId) && typeof opened.resolveRuntimeRequest === 'function';
}

Try / catch

try { await pumpEvents(opened); }
catch (e) { if (String(e.message).includes('not resolvable')) { failPendingCanonicalRequests(opened, e); } else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/0f18da8af96039dc. Report an issue: GitHub.