anomalyco/sst · error · VisibleError

The listen protocol " " must match the forward protocol " ".

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.

Solutions

  1. Change the forward protocol to the same family as the listen protocol (e.g. forward "80/http" for an https listener)
  2. Remove the forward override entirely so it defaults from the listen value (`forwardParts = listenParts`)
  3. 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

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


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/4542bf1772f9ec38. Report an issue: GitHub.

Appendix: 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)