vercel/ai · error · HarnessCapabilityUnsupportedError

The claude-code harness needs a TCP port exposed by the sand

Error message

The claude-code harness needs a TCP port exposed by the sandbox. Create the sandbox with `ports: [<port>]` or pass `createClaudeCode({ port })`.

What it means

`resolveBridgePort` determines the TCP port the harness uses to reach the Claude Code bridge inside the sandbox: an explicit `port` override wins, otherwise the first port in `sandboxSession.ports` is used. When neither exists — no override and the sandbox exposes no ports — it throws `HarnessCapabilityUnsupportedError` (harnessId `claude-code`) telling you to expose a port.

Source

Thrown at packages/harness-claude-code/src/claude-code-harness.ts:1204

        mcpServers: settings.mcpServers,
        supportsUserMessageResponses: () => supportsUserMessageResponses,
      });
    },
  };
}

function resolveBridgePort({
  sandboxSession,
  override,
}: {
  sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;
  override: number | undefined;
}): number {
  if (override !== undefined) return override;
  if ('ports' in sandboxSession && sandboxSession.ports.length > 0) {
    return sandboxSession.ports[0];
  }
  throw new HarnessCapabilityUnsupportedError({
    harnessId: 'claude-code',
    message:
      'The claude-code harness needs a TCP port exposed by the sandbox. ' +
      'Create the sandbox with `ports: [<port>]` or pass `createClaudeCode({ port })`.',
  });
}

function validateBasicSandboxSettings({
  sandboxSession,
  port,
  portEndpoint,
}: {
  sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;
  port: number | undefined;
  portEndpoint: HarnessV1PortEndpoint | undefined;
}): void {
  if ('getPortEndpoint' in sandboxSession) return;
  if (port == null) {

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Pass an explicit port: `createClaudeCode({ port: 3000 })` matching the port the agent listens on in the sandbox.
  2. Recreate the sandbox with the port exposed, e.g. `createSandbox({ ports: [3000] })`, so `sandboxSession.ports[0]` exists.
  3. Use a sandbox session that exposes `getPortEndpoint` (network sandbox session) so port resolution happens via the endpoint instead.
  4. Verify with your sandbox provider how/when ports are allocated; ensure ports are declared at session creation time.

Example fix

// before
const sandbox = await createSandbox({});
createClaudeCode({ sandboxSession: sandbox });
// after
const sandbox = await createSandbox({ ports: [3000] });
createClaudeCode({ sandboxSession: sandbox }); // or add { port: 3000 }
Defensive patterns

Strategy: validation

Validate before calling

function assertBridgePortResolvable(sandboxSession, port) {
  if (port !== undefined) return;
  const ports = sandboxSession && 'ports' in sandboxSession ? sandboxSession.ports : [];
  if (!Array.isArray(ports) || ports.length === 0) {
    throw new TypeError('Provide createClaudeCode({ port }) or create the sandbox with ports: [<port>]');
  }
}
assertBridgePortResolvable(sandboxSession, settings.port);

Type guard

function sandboxExposesPorts(session) {
  return typeof session === 'object' && session !== null &&
    'ports' in session && Array.isArray(session.ports) && session.ports.length > 0;
}

Try / catch

try {
  return createClaudeCode({ sandboxSession, ...settings });
} catch (err) {
  if (err?.name === 'HarnessCapabilityUnsupportedError' && err.message.includes('TCP port exposed by the sandbox')) {
    return createClaudeCode({ sandboxSession, port: DEFAULT_BRIDGE_PORT, ...settings });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `createClaudeCode({ sandboxSession })` (no `port` option) where the sandbox session's `ports` array is empty or absent, so there is no port to route bridge traffic through.

Common situations: Creating a sandbox without `ports: [<port>]` and forgetting the `port` option; a sandbox provider that allocates ports lazily so `ports` is empty at harness construction; typos like `port: 0` intending 'auto' (0 is falsy but `undefined`-checked, so check the actual provider semantics).

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/667d98e031e487a0. Report an issue: GitHub.