anomalyco/sst · error · VisibleError
Target group "${tgtId}" not found. Ensure the forward port m
Error message
Target group "${tgtId}" not found. Ensure the forward port matches in Service "${name}". What it means
When a Service is attached to an existing ALB via loadBalancer rules, each rule's `forward` port/protocol must match a target group that the Service created for one of its exposed ports. The component builds a key from the rule's forward port/protocol/container and looks it up in the map of ALB target groups; if nothing matches, it throws this VisibleError so the misconfiguration is caught at synth/deploy time instead of producing an invalid listener rule.
Source
Thrown at platform/src/components/aws/service.ts:2763
) {
throw new VisibleError(
`At least one condition (path, query, or header) must be set for rules on an external ALB in Service "${name}".`,
);
}
const listenerParts = rule.listen.split("/");
const listenerPort = parseInt(listenerParts[0]);
const listenerProtocol = listenerParts[1];
const forwardParts = rule.forward.split("/");
const forwardPort = parseInt(forwardParts[0]);
const forwardProtocol = forwardParts[1].toUpperCase();
const containerNameForKey = rule.container ?? name;
const tgtId = targetKey(containerNameForKey, forwardProtocol, forwardPort);
const targetGroup = albTargets[tgtId];
if (!targetGroup) {
throw new VisibleError(
`Target group "${tgtId}" not found. Ensure the forward port matches in Service "${name}".`,
);
}
const listenerResource =
attachment.instance.getListener(listenerProtocol, listenerPort);
new lb.ListenerRule(
...transform(
args.transform?.listenerRule,
`${name}AlbRule${listenerProtocol.toUpperCase()}${listenerPort}P${rule.priority}`,
{
listenerArn: listenerResource.arn,
priority: rule.priority,
actions: [
{
type: "forward",
targetGroupArn: targetGroup.arn,View on GitHub (pinned to a0bd20f762)
Solutions
- Check the rule's `forward` port in the Service's loadBalancer attachment and make it exactly match a port exposed by the target container (e.g. change `forward: "8080/http"` to `forward: "3000/http"`).
- Verify the protocol in `forward` matches the protocol the Service exposes for that port (http vs https).
- If the rule forwards to a non-default container, set `container` on the rule to the container that actually exposes the port.
- Confirm the target container declares that port in its `ports`/public ports configuration so the Service creates the target group.
Example fix
// before
loadBalancer: {
rules: [{ listen: "443/https", forward: "8080/http", conditions: { path: "/api/*" } }]
}
// after
loadBalancer: {
rules: [{ listen: "443/https", forward: "3000/http", conditions: { path: "/api/*" } }]
} Defensive patterns
Strategy: validation
Validate before calling
const svcPorts = container.ports?.map(p => `${p.port}/${p.protocol ?? "http"}`) ?? [];
if (!svcPorts.includes(rule.forward)) {
throw new Error(`Rule forward "${rule.forward}" must match an exposed Service port (${svcPorts.join(", ")})`);
} Type guard
function hasMatchingTargetGroup(albTargets: Record<string, unknown>, rule: { forward: string; container?: string }, svcName: string): boolean {
const [port, proto] = rule.forward.split("/");
const key = targetKey(rule.container ?? svcName, (proto ?? "http").toUpperCase(), parseInt(port, 10));
return key in albTargets;
} Try / catch
try {
await deploy();
} catch (e) {
if (e instanceof VisibleError && e.message.includes("Target group") && e.message.includes("not found")) {
console.error("ALB rule forward port does not match an exposed service port:", e.message);
}
throw e;
} Prevention
- Keep a single source of truth for container ports and derive both the ports config and the loadBalancer forward values from it.
- Verify forward port/protocol string exactly matches a declared public port (e.g. "3000/http").
- When forwarding to a non-primary container, always set the rule's `container` field explicitly.
- Review loadBalancer rule diffs when renaming containers or changing ports.
When it happens
Trigger: Setting a loadBalancer rule whose `forward` port (or protocol, or container name) does not correspond to any port exposed by the Service's containers — e.g. `forward: "8080/http"` while the container only exposes/exactly registers port 3000, a protocol mismatch like `forward: "3000/https"` when the target group was created as http, or a `container` field that names a container that has no such port.
Common situations: Copy-pasting an ALB rule from another service and forgetting to update the forward port; renaming a container so the default container-name key no longer matches; typo in port; assuming any forward port works without declaring the port in the container's ports list.
Related errors
- Cannot access `nodes.loadBalancer` when no public ports are
- You must provide the ports to expose via "loadBalancer.rules
- You must provide a container name in "loadBalancer.rules" wh
- Cannot access `nodes.loadBalancer` in dev mode.
- The ALB VPC "${albVpcId}" does not match the cluster VPC "${
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/3fe6362a2f48ac8f.
Report an issue: GitHub.