anomalyco/sst · error · VisibleError

Cannot access `nodes.loadBalancer` when no public ports are

Error message

Cannot access `nodes.loadBalancer` when no public ports are exposed.

What it means

The Service only creates an Elastic Load Balancer when public ports are exposed (e.g. via the `loadBalancer` args). When none are configured, `self.loadBalancer` is undefined and the getter throws this VisibleError rather than returning `undefined`, since the component cannot silently hand back a missing node.

Source

Thrown at platform/src/components/aws/service.ts:2912

       * The Amazon ECS Task Definition.
       */
      get taskDefinition() {
        if (self.dev)
          throw new VisibleError(
            "Cannot access `nodes.taskDefinition` in dev mode.",
          );
        return self.taskDefinition!;
      },
      /**
       * The Amazon Elastic Load Balancer.
       */
      get loadBalancer() {
        if (self.dev)
          throw new VisibleError(
            "Cannot access `nodes.loadBalancer` in dev mode.",
          );
        if (!self.loadBalancer)
          throw new VisibleError(
            "Cannot access `nodes.loadBalancer` when no public ports are exposed.",
          );
        return self.loadBalancer;
      },
      /**
       * The Amazon Application Auto Scaling target.
       */
      get autoScalingTarget() {
        if (self.dev)
          throw new VisibleError(
            "Cannot access `nodes.autoScalingTarget` in dev mode.",
          );
        return self.autoScalingTarget!;
      },
      /**
       * The Amazon Cloud Map service.
       */
      get cloudmapService() {

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Expose public ports by providing the `loadBalancer` (or `ports`) argument when creating the Service so the ALB is actually created.
  2. If the service is intentionally private, remove the `nodes.loadBalancer` reference and wire any listener/DNS through another component.
  3. Conditionally access the node only when your config actually sets a load balancer.

Example fix

// before
const lb = service.nodes.loadBalancer;

// after (option A: expose ports)
const service = new sst.aws.Service("Api", {
  cluster,
  loadBalancer: { ports: [{ listen: "80/http" }] },
});
const lb = service.nodes.loadBalancer;
// or (option B: guard)
const lb = withLoadBalancer ? service.nodes.loadBalancer : undefined;
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the Service was created with a load balancer before reading the node
const service = new sst.aws.Service("Api", {
  cluster,
  loadBalancer: { ports: [{ listen: "80/http" }] },
});
// only then:
const lb = service.nodes.loadBalancer;

Try / catch

try {
  const lb = service.nodes.loadBalancer;
} catch (e) {
  if (String(e).includes("no public ports")) {
    // service is private; use alternative routing or skip
  } else throw e;
}

Prevention

When it happens

Trigger: Reading `service.nodes.loadBalancer` on a Service created without a `loadBalancer`/public `ports` configuration, in deploy mode (not dev).

Common situations: A developer assumes every Service gets an ALB and references `nodes.loadBalancer` for a listener rule or Route53 alias, but the service was declared as internal / non-HTTP (e.g. queue worker or private gRPC service).

Related errors


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