{"record":{"id":"e893525d5bd5f89b","repo":"anomalyco/sst","slug":"you-must-provide-a-custom-domain-for-port-listen","errorCode":null,"errorMessage":"You must provide a custom domain for ${port.listenProtocol.toUpperCase()} protocol.","messagePattern":"You must provide a custom domain for (.+?) protocol\\.","errorType":"validation","errorClass":"VisibleError","httpStatus":null,"severity":"error","filePath":"platform/src/components/aws/service-v1.ts","lineNumber":274,"sourceCode":"            forwardProtocol: forwardParts[1],\n          };\n        });\n\n        // validate protocols are consistent\n        const appProtocols = ports.filter(\n          (port) =>\n            [\"http\", \"https\"].includes(port.listenProtocol) &&\n            [\"http\", \"https\"].includes(port.forwardProtocol),\n        );\n        if (appProtocols.length > 0 && appProtocols.length < ports.length)\n          throw new VisibleError(\n            `Protocols must be either all http/https, or all tcp/udp/tcp_udp/tls.`,\n          );\n\n        // validate certificate exists for https/tls protocol\n        ports.forEach((port) => {\n          if ([\"https\", \"tls\"].includes(port.listenProtocol) && !pub.domain) {\n            throw new VisibleError(\n              `You must provide a custom domain for ${port.listenProtocol.toUpperCase()} protocol.`,\n            );\n          }\n        });\n\n        return ports;\n      });\n\n      const domain = output(args.public).apply((pub) => {\n        if (!pub.domain) return undefined;\n\n        // normalize domain\n        const domain =\n          typeof pub.domain === \"string\" ? { name: pub.domain } : pub.domain;\n        return {\n          name: domain.name,\n          dns: domain.dns === false ? undefined : domain.dns ?? awsDns(),\n          cert: domain.cert,","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/platform/src/components/aws/service-v1.ts#L256-L292","documentation":"Ports listening on https or tls require TLS termination at a custom domain. If a port's listen protocol is https/tls but `public.domain` is not set, normalizePublic throws, since the load balancer has no certificate to serve HTTPS/TLS without a domain.","triggerScenarios":"`public.ports` contains `\"443/https\"` or `\"443/tls\"` while `public.domain` is undefined; forgetting `domain` when switching a port from http to https.","commonSituations":"Adding TLS to an existing service; assuming a default AWS-provided domain supports https; missing certificate/hostname config.","solutions":["Add `domain` to the `public` block, e.g. `public: { domain: \"api.example.com\", ports: [...] }`","Or change the listen protocol to `http` if TLS isn't needed at the LB","Ensure a certificate for the domain is available in the region (Route53/ACM)"],"exampleFix":"// before\npublic: { ports: [{ listen: \"443/https\", forward: \"8080/http\" }] }\n// after\npublic: { domain: \"api.example.com\", ports: [{ listen: \"443/https\", forward: \"8080/http\" }] }","handlingStrategy":"validation","validationCode":"const needsDomain = args.public?.ports?.some(p => /^(443\\/)?(https|tls)/.test(p.listen));\nif (needsDomain && !args.public?.domain) throw new Error(\"https/tls ports require public.domain\");","typeGuard":"function needsDomain(pub?: { ports?: { listen: string }[]; domain?: string }): boolean {\n  return !!pub?.ports?.some(p => [\"https\",\"tls\"].includes(p.listen.split(\"/\")[1])) && !pub.domain;\n}","tryCatchPattern":null,"preventionTips":["Set `public.domain` whenever any port listens on https/tls","Provision an ACM certificate for the domain in the deployment region","Switch to plain http during prototyping, add domain+TLS later"],"tags":["tls","https","domain","certificate"],"backgroundTag":"missing-custom-domain","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}