vercel/ai · error · HarnessCapabilityUnsupportedError
Port ${options.port} is not exposed on this sandbox. Exposed
Error message
Port ${options.port} is not exposed on this sandbox. Exposed ports: [${exposedPorts.join(', ')}]. What it means
Vercel sandbox sessions can only expose ports declared when the sandbox was created. getPortEndpoint validates the requested port against the session's exposed ports list and throws HarnessCapabilityUnsupportedError when the port was never exposed, listing the ports that are available.
Source
Thrown at packages/sandbox-vercel/src/vercel-network-sandbox-session.ts:56
sandbox: input.sandbox,
});
}
get ports(): ReadonlyArray<number> {
return this.sandbox.routes.map(route => route.port);
}
restricted(): SandboxSession {
return new VercelSandboxSession(this.sandbox);
}
getPortEndpoint = async (options: {
port: number;
protocol?: 'http' | 'https' | 'ws';
}): Promise<HarnessV1PortEndpoint> => {
const exposedPorts = this.ports;
if (!exposedPorts.includes(options.port)) {
throw new HarnessCapabilityUnsupportedError({
harnessId: VERCEL_PROVIDER_ID,
message: `Port ${options.port} is not exposed on this sandbox. Exposed ports: [${exposedPorts.join(', ')}].`,
});
}
const protocol = options.protocol ?? 'https';
const url = new URL(this.sandbox.domain(options.port));
const isSecure = url.protocol === 'https:';
switch (protocol) {
case 'http':
url.protocol = isSecure ? 'https:' : 'http:';
break;
case 'https':
url.protocol = 'https:';
break;
case 'ws':
url.protocol = isSecure ? 'wss:' : 'ws:';
break;
}View on GitHub (pinned to 69428b1f8b)
Solutions
- Add the required port to the sandbox's exposed ports when creating it
- Request one of the ports listed in the error message
- Align your server's listening port with an exposed port
- Catch HarnessCapabilityUnsupportedError and surface the available ports
Example fix
// before
const sandbox = vercelSandbox({});
await sandbox.getPortEndpoint({ port: 3000 });
// after
const sandbox = vercelSandbox({ ports: [3000] });
await sandbox.getPortEndpoint({ port: 3000 }); Defensive patterns
Strategy: validation
Validate before calling
function assertPortExposed(session, port) {
const exposed = session.ports ?? [];
if (!exposed.includes(port)) {
throw new Error(`Port ${port} not exposed. Exposed ports: [${exposed.join(', ')}].`);
}
}
// call before getPortEndpoint Type guard
function isPortNotExposed(e) {
return typeof e === 'object' && e !== null && e.constructor?.name === 'HarnessCapabilityUnsupportedError' && /not exposed/.test(String(e.message));
} Try / catch
try {
endpoint = await session.getPortEndpoint({ port });
} catch (e) {
if (isPortNotExposed(e)) {
throw new Error(`Configure ports [${port}] when creating the sandbox. ${e.message}`);
}
throw e;
} Prevention
- Declare every port your app listens on in the sandbox's ports option
- Keep the server's listening port and the requested port in a single constant
- Log the exposed-ports list from the error to debug config mismatches
When it happens
Trigger: Calling getPortEndpoint({ port: N }) where N is not in the sandbox's configured exposed ports (this.ports) — e.g. requesting 3000 when only 8080 was exposed.
Common situations: Sandbox created without the port the app listens on; default-port mismatch (app binds 3000 but sandbox exposes 8080); typos in port configuration.
Related errors
- The Claude Code harness cannot use `mintBridgeToken` with a
- The Claude Code harness requires an explicit `port` when usi
- The Claude Code harness requires an explicit `portEndpoint`
- The deepagents harness cannot use `mintBridgeToken` with a s
- The deepagents harness needs a TCP port exposed by the sandb
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/764bb3daa4033ea5.
Report an issue: GitHub.