{"record":{"id":"fbc48e17530ae3db","repo":"paperclipai/paperclip","slug":"environment-driver-driver-driver-does-not-sup-fbc48e","errorCode":null,"errorMessage":"Environment driver \"${driver.driver}\" does not support duplex channels.","messagePattern":"Environment driver \"(.+?)\" does not support duplex channels\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/environment-runtime.ts","lineNumber":3474,"sourceCode":"        throw new Error(`Environment driver \"${driver.driver}\" does not support native file sync.`);\n      }\n      return await driver.syncIn(input);\n    },\n\n    async syncOut(input: EnvironmentDriverSyncInput): Promise<PluginEnvironmentSyncResult> {\n      const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));\n      if (!driver.syncOut) {\n        throw new Error(`Environment driver \"${driver.driver}\" does not support native file sync.`);\n      }\n      return await driver.syncOut(input);\n    },\n\n    async openDuplexChannel(\n      input: EnvironmentDriverOpenDuplexChannelInput,\n    ): Promise<CommandManagedDuplexChannel> {\n      const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));\n      if (!driver.openDuplexChannel) {\n        throw new Error(`Environment driver \"${driver.driver}\" does not support duplex channels.`);\n      }\n      // Centralize the duplex channel authorization here. Resolve the exact lease\n      // capability snapshot and refuse unless the effective snapshot grants the\n      // opt-in `duplexCommandStream` capability. This gate runs before the driver\n      // call, so an unauthorized lease never reaches the worker. The\n      // execution-target member gate stays as defense in depth. A driver that\n      // cannot resolve the snapshot fails closed with the fixed refusal.\n      const effective =\n        (await driver.effectiveSandboxCapabilities?.(input)) ?? null;\n      if (effective?.duplexCommandStream !== true) {\n        throw new Error(DUPLEX_CHANNEL_CAPABILITY_DENIED);\n      }\n      return await driver.openDuplexChannel(input);\n    },\n  };\n}\n\nexport type EnvironmentRuntimeService = ReturnType<typeof environmentRuntimeService>;","sourceCodeStart":3456,"sourceCodeEnd":3492,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/services/environment-runtime.ts#L3456-L3492","documentation":"Thrown by the environment runtime's openDuplexChannel facade when the resolved driver for the lease does not implement openDuplexChannel (server/src/services/environment-runtime.ts:3474). Driver support is optional: only the plugin-backed sandbox driver provides duplex channels today; drivers like the local process driver expose syncOut/execute only. The check mirrors the native file sync guard above it (\"does not support native file sync\").","triggerScenarios":"Calling openDuplexChannel on the runtime facade for a lease whose driver key resolves to a driver without an openDuplexChannel method — e.g. a local/docker environment lease, or a plugin sandbox driver instantiated without a pluginWorkerManager.","commonSituations":"Code written against plugin sandboxes run against local dev environments; a custom driver registered without duplex support; attempting interactive streaming against a driver that only supports one-shot execute.","solutions":["Feature-detect before calling: check typeof driver.openDuplexChannel === \"function\" or gate on the lease being a plugin sandbox lease.","Use the driver's supported execution path (execute) when duplex is unavailable.","Provision the environment with the plugin sandbox provider driver if duplex streaming is required.","For custom drivers, implement openDuplexChannel (and effectiveSandboxCapabilities) to opt into the feature."],"exampleFix":"// before\nconst ch = await envRuntime.openDuplexChannel({ lease, environment, command }); // throws for local driver\n\n// after\nconst duplexSupported = typeof getDriver(getLeaseDriverKey(lease, environment))?.openDuplexChannel === \"function\";\nif (!duplexSupported) {\n  await envRuntime.execute({ lease, environment, command });\n} else {\n  const ch = await envRuntime.openDuplexChannel({ lease, environment, command });\n}","handlingStrategy":"type-guard","validationCode":"const driverKey = getLeaseDriverKey(lease, environment);\nconst driver = requireDriverKey(driverKey);\nif (typeof driver.openDuplexChannel !== \"function\") { return await runtime.execute({ lease, environment, command }); }","typeGuard":"function driverSupportsDuplex(driver: { openDuplexChannel?: unknown }): boolean {\n  return typeof driver.openDuplexChannel === \"function\";\n}","tryCatchPattern":"try { return await runtime.openDuplexChannel(input); } catch (err) { if (/does not support duplex channels/.test((err as Error).message)) { return await runtime.execute(input); /* degrade to one-shot */ } throw err; }","preventionTips":["Feature-detect driver capabilities instead of assuming all environments support duplex streaming.","Provision plugin sandbox environments when interactive command streams are required.","Keep driver capability checks next to call sites so unsupported drivers degrade gracefully."],"tags":["environment","duplex-channel","driver","capability-detection","unsupported-operation"],"backgroundTag":"unsupported-driver-operation","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-21T17:58:32.592Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}