anomalyco/sst · error · VisibleError
The listen protocol "${v.listen}" must match the forward pro
Error message
The listen protocol "${v.listen}" must match the forward protocol "${v.forward}". What it means
SST's Service load balancer requires that when you override the forward protocol for a rule, it must belong to the same protocol family (application http/https vs network tcp/udp/tcp_udp/tls) as the listen protocol. An ALB/Fargate listener cannot forward to a target group of an incompatible protocol type, so normalizeLoadBalancer rejects the mix at synth time.
Source
Thrown at platform/src/components/aws/service.ts:2010
)
throw new VisibleError(
`The listen protocol "${v.listen}" must match the redirect protocol "${v.redirect}".`,
);
return {
type: "redirect" as const,
listenPort,
listenProtocol,
listenConditions,
redirectPort,
redirectProtocol,
};
}
const forwardParts = v.forward ? v.forward.split("/") : listenParts;
const forwardPort = forwardParts && parseInt(forwardParts[0]);
const forwardProtocol = forwardParts && forwardParts[1];
if (protocolType(listenProtocol) !== protocolType(forwardProtocol))
throw new VisibleError(
`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)View on GitHub (pinned to a0bd20f762)
Solutions
- Change the forward protocol to the same family as the listen protocol (e.g. forward "80/http" for an https listener)
- Remove the forward override entirely so it defaults from the listen value (`forwardParts = listenParts`)
- If you truly need cross-protocol forwarding, split into rules that keep families consistent
Example fix
// before
{ listen: "443/https", forward: "80/tcp" }
// after
{ listen: "443/https", forward: "80/http" } Defensive patterns
Strategy: validation
Validate before calling
function isApplication(p) { return ["http","https"].includes(p?.split("/")[1]); }
for (const r of config.loadBalancer.rules) {
const lp = r.listen.split("/")[1];
const fp = r.forward ? r.forward.split("/")[1] : lp;
if ((isApplication(lp)) !== (isApplication(fp))) throw new Error(`rule ${r.listen} -> ${r.forward}: protocols must be same family`);
} Type guard
const protocolFamily = (p?: string) => p === undefined ? undefined : ["http","https"].includes(p) ? "application" : ["tcp","udp","tcp_udp","tls"].includes(p) ? "network" : "unknown";
Try / catch
null
Prevention
- Omit forward and let it inherit from listen whenever possible
- Keep a comment on each rule noting the protocol family
- Validate rule configs in CI with a schema (zod) that constrains protocol pairs
When it happens
Trigger: Defining a loadBalancer.rules entry like listen: "443/https" with forward: "80/tcp", or listen "8080/tls" with forward "80/http" — the protocolType() comparison fails before any AWS resources are created.
Common situations: Copy-pasting listener configs from classic ELB examples; assuming the forward side defaults independently of the listen side; mixing an HTTPS public listener with a TCP container port.
Related errors
- Unsupported storage: ${v}. The supported value for storage i
- type === "service" ? `You cannot provide both "containers" a
- Protocols must be either all http/https, or all tcp/udp/tcp_
- Lifecycle rule at index ${index} has an empty or whitespace-
- The DNS record "${partial.name}" cannot be created because t
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/4542bf1772f9ec38.
Report an issue: GitHub.