paperclipai/paperclip · error

DUPLEX_CHANNEL_CAPABILITY_DENIED

DUPLEX_CHANNEL_CAPABILITY_DENIED

Error message

Sandbox lease does not grant the duplex command stream capability.

What it means

Authorization refusal for duplex channels, centralized in the runtime facade: before delegating to the driver it resolves the lease's effective sandbox capability snapshot via driver.effectiveSandboxCapabilities and requires the opt-in duplexCommandStream capability to be exactly true (server/src/services/environment-runtime.ts:3485, constant DUPLEX_CHANNEL_CAPABILITY_DENIED). A missing snapshot, a snapshot without the capability, or a driver that cannot resolve capabilities all fail closed — unauthorized leases never reach the worker.

Source

Thrown at server/src/services/environment-runtime.ts:3485

    },

    async openDuplexChannel(
      input: EnvironmentDriverOpenDuplexChannelInput,
    ): Promise<CommandManagedDuplexChannel> {
      const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));
      if (!driver.openDuplexChannel) {
        throw new Error(`Environment driver "${driver.driver}" does not support duplex channels.`);
      }
      // Centralize the duplex channel authorization here. Resolve the exact lease
      // capability snapshot and refuse unless the effective snapshot grants the
      // opt-in `duplexCommandStream` capability. This gate runs before the driver
      // call, so an unauthorized lease never reaches the worker. The
      // execution-target member gate stays as defense in depth. A driver that
      // cannot resolve the snapshot fails closed with the fixed refusal.
      const effective =
        (await driver.effectiveSandboxCapabilities?.(input)) ?? null;
      if (effective?.duplexCommandStream !== true) {
        throw new Error(DUPLEX_CHANNEL_CAPABILITY_DENIED);
      }
      return await driver.openDuplexChannel(input);
    },
  };
}

export type EnvironmentRuntimeService = ReturnType<typeof environmentRuntimeService>;

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Grant the duplexCommandStream capability in the environment/sandbox configuration the lease is derived from, then acquire a new lease.
  2. Verify with the driver's effectiveSandboxCapabilities (or equivalent API) that the resolved snapshot shows duplexCommandStream === true before opening the channel.
  3. If the snapshot unexpectedly resolves to null, fix the capability resolution path on the driver — absence is treated as denial by design.
  4. Callers that do not need interactive streaming should use execute instead of requesting the capability.

Example fix

// before
await envRuntime.openDuplexChannel({ lease, environment, command }); // DUPLEX_CHANNEL_CAPABILITY_DENIED

// after (opt in at environment config / lease acquisition)
const lease = await acquireSandboxLease(environment, {
  capabilities: { duplexCommandStream: true },
});
await envRuntime.openDuplexChannel({ lease, environment, command });
Defensive patterns

Strategy: validation

Validate before calling

const effective = (await driver.effectiveSandboxCapabilities?.({ lease, environment, command })) ?? null;
if (effective?.duplexCommandStream !== true) throw new Error("Lease lacks duplexCommandStream; opt the environment/lease in before opening a channel.");

Type guard

function leaseGrantsDuplex(snapshot: { duplexCommandStream?: unknown } | null | undefined): boolean {
  return snapshot?.duplexCommandStream === true;
}

Try / catch

try { return await runtime.openDuplexChannel(input); } catch (err) { if ((err as Error).message === "Sandbox lease does not grant the duplex command stream capability.") { throw new PermissionError("Opt the lease into duplexCommandStream and re-acquire it."); } throw err; }

Prevention

When it happens

Trigger: openDuplexChannel on a lease whose effective capability snapshot does not include duplexCommandStream: true — capability never opted in at lease/environment creation, revoked since acquisition, or the driver cannot resolve a snapshot (returns undefined → null → denied). Reached only after the driver-support check passed.

Common situations: New deployments enabling duplex-based tooling without opting leases into the capability; capability gates rolled out server-side before configurations were updated; tests using bare leases without capability metadata.

Related errors


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-21). Data as JSON: /api/errors/ec727a874bad4398. Report an issue: GitHub.