anomalyco/sst · error · VisibleError
You must provide a custom domain for ${rule.listenProtocol.t
Error message
You must provide a custom domain for ${rule.listenProtocol.toUpperCase()} protocol. What it means
HTTPS and TLS listeners terminate TLS and therefore need a certificate, which SST provisions through the lb.domain property. If any rule listens on https or tls but no custom domain is configured, SST cannot issue/attach a cert and throws before deployment.
Source
Thrown at platform/src/components/aws/service.ts:2036
forwardPort,
forwardProtocol,
container: v.container ?? containers[0].name,
};
});
// validate protocols are consistent
const appProtocols = rules.filter(
(rule) => protocolType(rule.listenProtocol) === "application",
);
if (appProtocols.length > 0 && appProtocols.length < rules.length)
throw new VisibleError(
`Protocols must be either all http/https, or all tcp/udp/tcp_udp/tls.`,
);
// validate certificate exists for https/tls protocol
rules.forEach((rule) => {
if (["https", "tls"].includes(rule.listenProtocol) && !lb.domain) {
throw new VisibleError(
`You must provide a custom domain for ${rule.listenProtocol.toUpperCase()} protocol.`,
);
}
});
return rules;
},
);
// normalize domain
const domain = output(inlineLoadBalancer).apply((lb) => {
if (!lb.domain) return undefined;
// normalize domain
const domain =
typeof lb.domain === "string" ? { name: lb.domain } : lb.domain;
return {
name: domain.name,View on GitHub (pinned to a0bd20f762)
Solutions
- Add a domain to the load balancer config, e.g. domain: "api.example.com"
- Switch the rule to a plain http/tcp protocol if TLS termination isn't actually needed
- Attach to an existing ALB/cert setup where the domain is provided
Example fix
// before
loadBalancer: { ports: { "80/http": "app:3000" }, rules: [{ listen: "443/https", forward: "80/http" }] }
// after
loadBalancer: { domain: "api.example.com", ports: { "80/http": "app:3000" }, rules: [{ listen: "443/https", forward: "80/http" }] } Defensive patterns
Strategy: validation
Validate before calling
for (const r of config.loadBalancer.rules) {
const proto = r.listen.split("/")[1];
if (["https","tls"].includes(proto) && !config.loadBalancer.domain)
throw new Error(`rule ${r.listen} requires loadBalancer.domain`);
} Type guard
const needsDomain = (listen: string) =>
["https","tls"].includes(listen.split("/")[1]); Try / catch
null
Prevention
- Always set domain when any listener is https/tls
- Prefer http internally and terminate TLS at one place
- Add a config schema requiring domain when https/tls protocols are present
When it happens
Trigger: Any loadBalancer.rules entry with listen "443/https" or "9000/tls" (external ALB attachment included) while the Service's loadBalancer.domain (or the shared ALB's domain) is undefined.
Common situations: Testing TLS locally without a domain; forgetting that shared/external ALB domains must be declared where SST expects them; renaming the domain field during refactors.
Related errors
- You must provide a custom domain for ${port.listenProtocol.t
- Missing "name" for domain.
- Need to provide a validated certificate via "cert" when DNS
- The DNS record "${partial.name}" cannot be created because t
- You must provide the ports to expose via "public.ports".
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/01311c2cda348b82.
Report an issue: GitHub.