openclaw/openclaw · error · Error
Pi terminal command requires duplex transport
Error message
Pi terminal command requires duplex transport
What it means
Thrown by resumePiSession (the node-host command handler for PI_TERMINAL_RESUME_COMMAND) when the optional io argument is undefined. The resume command spawns a PTY via runNodePtyCommand, which needs duplex stdin/stdout transport to forward bytes both ways; a request that arrives without an io channel cannot satisfy that contract.
Source
Thrown at extensions/acpx/src/pi-session-catalog-runtime.ts:560
hostId: request.hostId,
label: nodeLabel(node),
};
}
export async function listPiSessions(paramsJSON?: string | null): Promise<string> {
return JSON.stringify(await listLocalPiSessionPage(parseNodeParams(paramsJSON)));
}
export async function readPiSession(paramsJSON?: string | null): Promise<string> {
return JSON.stringify(await readLocalPiTranscriptPage(parseNodeParams(paramsJSON)));
}
export async function resumePiSession(
paramsJSON?: string | null,
io?: OpenClawPluginNodeHostCommandIo,
): Promise<string> {
if (!io) {
throw new Error("Pi terminal command requires duplex transport");
}
const params = decodeNodePtyResumeParams(paramsJSON, validatePiThreadId);
const record = await requireLocalPiSession(params.threadId);
const resolution = resolveNodeHostExecutable("pi", {
env: process.env,
pathEnv: process.env.PATH ?? process.env.Path ?? "",
strategy: "direct",
});
if (!resolution) {
throw new Error("Pi CLI is unavailable");
}
return JSON.stringify(
await runNodePtyCommand(
{
file: resolution.executable,
args: ["--session", params.threadId],
cwd: record.cwd,
cols: params.cols,View on GitHub (pinned to 01804a7531)
Solutions
- Only invoke PI_TERMINAL_RESUME_COMMAND through a node host transport that supplies duplex io.
- If calling resumePiSession directly in tests, pass a stub io object matching OpenClawPluginNodeHostCommandIo.
- Gate the resume command in the host manifest so it is only advertised when duplex transport is available.
- If your transport cannot do duplex, do not advertise the resume command.
Example fix
// before await resumePiSession(paramsJSON); // io omitted // after await resumePiSession(paramsJSON, duplexIo);
Defensive patterns
Strategy: type-guard
Validate before calling
function hasDuplexIo(io: unknown): io is OpenClawPluginNodeHostCommandIo {
return !!io && typeof io === "object" && typeof (io as any).read === "function" && typeof (io as any).write === "function";
}
if (!hasDuplexIo(io)) throw new TypeError("resumePiSession requires duplex io"); Type guard
function isOpenClawPluginNodeHostCommandIo(value: unknown): value is OpenClawPluginNodeHostCommandIo {
return !!value && typeof value === "object" &&
typeof (value as { read?: unknown }).read === "function" &&
typeof (value as { write?: unknown }).write === "function";
} Try / catch
if (!io) {
// respond with a transport-level error rather than spawning the resume command
return { ok: false, error: "duplex transport required" };
} Prevention
- Only advertise PI_TERMINAL_RESUME_COMMAND on transports that supply duplex io.
- In tests, always pass a stub io matching OpenClawPluginNodeHostCommandIo.
- Gate resume behind a capability flag so non-duplex hosts never invoke it.
When it happens
Trigger: A node host invoking the resume command over a one-shot request/response transport that does not provide OpenClawPluginNodeHostCommandIo. A test harness calling resumePiSession directly without passing io. A custom transport that forgot to wire duplex IO.
Common situations: The acpx plugin is invoked through a transport that only supports simple invoke (single request, single response). Misuse of the public node command handler in tests. A transport regression that stopped attaching io to duplex-eligible commands.
Related errors
- hostId is invalid
- paired-node Pi terminal is unavailable
- Pi session catalog hostId is invalid
- Pi CLI is unavailable
- Pi session is outside the session store supported by pi-acp
AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12).
Data as JSON: /api/errors/d2fb0176874c2333.
Report an issue: GitHub.