can1357/oh-my-pi · error

${errorMessage(first.error)}${outputSuffix()}

Error message

${errorMessage(first.error)}${outputSuffix()}

What it means

While racing the PTY-driven Claude run against the /v1/messages capture, if the capture side fails first (capture-error), this error surfaces the capture failure's message plus any captured output as context. It means the proxy/capture pipeline itself broke before a response exchange could be recorded.

Source

Thrown at packages/coding-agent/src/cli/claude-trace-cli.ts:769

			} catch (error) {
				ptyOutput += `\n[omp input write failed: ${errorMessage(error)}]\n`;
			}
		})();
		const captureRace = proxy.waitForCapture(timeoutMs).then(
			exchange => ({ kind: "capture" as const, exchange }),
			error => ({ kind: "capture-error" as const, error }),
		);
		const ptyRace = runPromise.then(
			() => ({ kind: "pty-exit" as const }),
			error => ({ kind: "pty-error" as const, error }),
		);
		const first = await Promise.race([captureRace, ptyRace]);
		if (first.kind === "capture") {
			await shutdownPty(session, runPromise);
			return first.exchange;
		}
		if (first.kind === "capture-error") {
			throw new Error(`${errorMessage(first.error)}${outputSuffix()}`);
		}
		const late = await Promise.race([captureRace, Bun.sleep(250).then(() => ({ kind: "late-timeout" as const }))]);
		if (late.kind === "capture") {
			await shutdownPty(session, runPromise);
			return late.exchange;
		}
		if (first.kind === "pty-error") {
			throw new Error(
				`Claude command failed before /v1/messages completed: ${errorMessage(first.error)}${outputSuffix()}`,
			);
		}
		throw new Error(`Claude command exited before /v1/messages completed${outputSuffix()}`);
	} finally {
		terminal.dispose();
		await proxy.stop();
	}
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the embedded errorMessage and outputSuffix() capture output in the thrown message to identify the underlying proxy failure.
  2. Free the proxy port (default 8080) or pass a different port if another proxy is bound.
  3. Verify NODE_TLS_REJECT_UNAUTHORIZED=0 and the debug cert env actually reached the spawned claude process.
  4. Retry the trace — transient network failures during capture produce this same path.

Example fix

// before: port conflict
$ omp claude-trace  # proxy on 8080 already used
// after
$ omp claude-trace --proxy-port 8123
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting the trace
const portFree = !(await Bun.$`ss -ltn`.quiet().nothrow().text()).includes(`:${proxyPort} `);
if (!portFree) throw new Error(`Proxy port ${proxyPort} already in use`);

Try / catch

try {
  const exchange = await runTrace();
} catch (err) {
  // message embeds the underlying capture error + output suffix — surface both
  logger.error("capture failed", { cause: (err as Error).message });
}

Prevention

When it happens

Trigger: The local CONNECT proxy or TLS bridge fails — port 8080 already in use, TLS handshake failure with Claude Code, or an exception inside the capture pipeline — and that rejection wins the Promise.race against the PTY session.

Common situations: Another process is already listening on the proxy port; the proxy cert/env injection didn't reach the spawned Claude process; network errors reaching api.anthropic.com through the proxy; firewall blocking loopback MITM.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f7c305dac2e43efe. Report an issue: GitHub.