anomalyco/sst · error · VisibleError
Protocols must be either all http/https, or all tcp/udp/tcp_
Error message
Protocols must be either all http/https, or all tcp/udp/tcp_udp/tls.
What it means
A single ALB listener set must be homogeneous: SST groups rules into application (http/https) or network (tcp/udp/tcp_udp/tls) listeners, and an Elastic Load Balancer cannot mix listener types in one load balancer configuration. normalizeLoadBalancer throws when some but not all rules are application-protocol rules.
Source
Thrown at platform/src/components/aws/service.ts:2029
`The listen protocol "${v.listen}" must match the forward protocol "${v.forward}".`,
);
return {
type: "forward" as const,
listenPort,
listenProtocol,
listenConditions,
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) => {View on GitHub (pinned to a0bd20f762)
Solutions
- Make all rules use http/https, or all use tcp/udp/tcp_udp/tls
- Move the odd-protocol listener into a separate Service or a separately defined load balancer
- Drop the rule that no longer applies
Example fix
// before
rules: [{ listen: "80/http" }, { listen: "8080/tcp" }]
// after
rules: [{ listen: "80/http" }, { listen: "8080/http" }] Defensive patterns
Strategy: validation
Validate before calling
const families = new Set(config.loadBalancer.rules.map(r =>
["http","https"].includes(r.listen.split("/")[1]) ? "app" : "network"));
if (families.size > 1) throw new Error("all rules must be http/https or all tcp/udp/tcp_udp/tls"); Type guard
const allSameFamily = (rules: { listen: string }[]) => {
const fam = (p: string) => ["http","https"].includes(p) ? "app" : "network";
return rules.every(r => fam(r.listen.split("/")[1]) === fam(rules[0].listen.split("/")[1]));
}; Try / catch
null
Prevention
- Standardize each service on one protocol family
- Split mixed-protocol workloads into separate Services
- Lint loadBalancer configs before deploy
When it happens
Trigger: Providing loadBalancer.rules where one rule listens on "80/http" and another on "8080/tcp", or "443/https" mixed with "9000/tls".
Common situations: Adding a gRPC/TLS port next to existing HTTP rules; migrating a service from HTTP to TCP listeners while leaving an old rule behind; merging configs from two services.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- The listen protocol "${v.listen}" must match the forward pro
- Lifecycle rule at index ${index} has an empty or whitespace-
- The DNS record "${partial.name}" cannot be created because t
- Unsupported storage: ${v}. The supported value for storage i
- type === "service" ? `You cannot provide both "containers" a
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/ae5bd71a47fa4bb6.
Report an issue: GitHub.