{"record":{"id":"764bb3daa4033ea5","repo":"vercel/ai","slug":"port-options-port-is-not-exposed-on-this-sandbo","errorCode":null,"errorMessage":"Port ${options.port} is not exposed on this sandbox. Exposed ports: [${exposedPorts.join(', ')}].","messagePattern":"Port (.+?) is not exposed on this sandbox\\. Exposed ports: \\[(.+?)\\]\\.","errorType":"exception","errorClass":"HarnessCapabilityUnsupportedError","httpStatus":null,"severity":"error","filePath":"packages/sandbox-vercel/src/vercel-network-sandbox-session.ts","lineNumber":56,"sourceCode":"      sandbox: input.sandbox,\n    });\n  }\n\n  get ports(): ReadonlyArray<number> {\n    return this.sandbox.routes.map(route => route.port);\n  }\n\n  restricted(): SandboxSession {\n    return new VercelSandboxSession(this.sandbox);\n  }\n\n  getPortEndpoint = async (options: {\n    port: number;\n    protocol?: 'http' | 'https' | 'ws';\n  }): Promise<HarnessV1PortEndpoint> => {\n    const exposedPorts = this.ports;\n    if (!exposedPorts.includes(options.port)) {\n      throw new HarnessCapabilityUnsupportedError({\n        harnessId: VERCEL_PROVIDER_ID,\n        message: `Port ${options.port} is not exposed on this sandbox. Exposed ports: [${exposedPorts.join(', ')}].`,\n      });\n    }\n    const protocol = options.protocol ?? 'https';\n    const url = new URL(this.sandbox.domain(options.port));\n    const isSecure = url.protocol === 'https:';\n    switch (protocol) {\n      case 'http':\n        url.protocol = isSecure ? 'https:' : 'http:';\n        break;\n      case 'https':\n        url.protocol = 'https:';\n        break;\n      case 'ws':\n        url.protocol = isSecure ? 'wss:' : 'ws:';\n        break;\n    }","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/sandbox-vercel/src/vercel-network-sandbox-session.ts#L38-L74","documentation":"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.","triggerScenarios":"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.","commonSituations":"Sandbox created without the port the app listens on; default-port mismatch (app binds 3000 but sandbox exposes 8080); typos in port configuration.","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"],"exampleFix":"// before\nconst sandbox = vercelSandbox({});\nawait sandbox.getPortEndpoint({ port: 3000 });\n// after\nconst sandbox = vercelSandbox({ ports: [3000] });\nawait sandbox.getPortEndpoint({ port: 3000 });","handlingStrategy":"validation","validationCode":"function assertPortExposed(session, port) {\n  const exposed = session.ports ?? [];\n  if (!exposed.includes(port)) {\n    throw new Error(`Port ${port} not exposed. Exposed ports: [${exposed.join(', ')}].`);\n  }\n}\n// call before getPortEndpoint","typeGuard":"function isPortNotExposed(e) {\n  return typeof e === 'object' && e !== null && e.constructor?.name === 'HarnessCapabilityUnsupportedError' && /not exposed/.test(String(e.message));\n}","tryCatchPattern":"try {\n  endpoint = await session.getPortEndpoint({ port });\n} catch (e) {\n  if (isPortNotExposed(e)) {\n    throw new Error(`Configure ports [${port}] when creating the sandbox. ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["sandbox","port-endpoint","configuration","vercel"],"backgroundTag":"port-not-exposed","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}