anomalyco/sst · error · VisibleError

Set "vpc.publicSubnets" on the Cluster to use "public" on th

Error message

Set "vpc.publicSubnets" on the Cluster to use "public" on the "${name}" Task.

What it means

When a Task is attached to an existing Cluster and marked `public: true`, the task's ENIs must land in public subnets so they get internet-facing IPs. normalizeVpc inspects the cluster's `vpc.publicSubnets` list and throws if it is empty or undefined, because a public task cannot be scheduled correctly in a VPC without public subnets.

Source

Thrown at platform/src/components/aws/task.ts:417

      // "vpc" is a Vpc component
      if (args.cluster.vpc instanceof Vpc) {
        const vpc = args.cluster.vpc;
        return {
          id: vpc.id,
          isSstVpc: true,
          publicSubnets: vpc.publicSubnets,
          containerSubnets: vpc.publicSubnets,
          securityGroups: vpc.securityGroups,
        };
      }

      // "vpc" is object
      return {
        id: output(args.cluster.vpc).apply((v) => v.id),
        isSstVpc: false,
        publicSubnets: output(args.cluster.vpc).apply((v) => {
          if (isPublic && !v.publicSubnets?.length)
            throw new VisibleError(
              `Set "vpc.publicSubnets" on the Cluster to use "public" on the "${name}" Task.`,
            );
          return (v.publicSubnets ?? []).map((v) => output(v));
        }),
        containerSubnets: output(args.cluster.vpc).apply((v) =>
          v.containerSubnets.map((v) => output(v)),
        ),
        securityGroups: output(args.cluster.vpc).apply((v) =>
          v.securityGroups.map((v) => output(v)),
        ),
      };
    }


    function createPublicSecurityGroup() {
      if (!isPublic) return;
      return new ec2.SecurityGroup(
        `${name}PublicSecurityGroup`,

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Set `publicSubnets` on the Cluster's `vpc` argument to an array of public subnet IDs.
  2. If the VPC is an SST `sst.aws.Vpc` reference, recreate/update it with `publicSubnets` configured and redeploy, then redeploy the app.
  3. If the task does not actually need to be public, set `public: false` so it can use private/container subnets.

Example fix

// before
new sst.aws.Cluster("Cluster", {
  vpc: { id: "vpc-123", containerSubnets: ["subnet-a"], privateSubnets: ["subnet-b"] }
});
new sst.aws.Task("Task", { cluster: cluster, public: true });
// after
new sst.aws.Cluster("Cluster", {
  vpc: {
    id: "vpc-123",
    containerSubnets: ["subnet-a"],
    privateSubnets: ["subnet-b"],
    publicSubnets: ["subnet-c"]
  }
});
new sst.aws.Task("Task", { cluster: cluster, public: true });
Defensive patterns

Strategy: validation

Validate before calling

const clusterVpc = { id: "vpc-123", publicSubnets: [], containerSubnets: ["subnet-a"] };
if (isPublicTask && (!clusterVpc.publicSubnets || clusterVpc.publicSubnets.length === 0)) {
  throw new Error("Cluster vpc must define publicSubnets for tasks with public: true");
}

Type guard

function hasPublicSubnets(v: { publicSubnets?: string[] }): v is { publicSubnets: string[] } {
  return Array.isArray(v.publicSubnets) && v.publicSubnets.length > 0;
}

Prevention

When it happens

Trigger: Creating `new sst.aws.Task("X", { cluster: <a cluster whose vpc has no publicSubnets>, public: true })`, or pointing the task at a Cluster built from a `vpc` object literal that omits `publicSubnets`.

Common situations: Using a VPC created with only private subnets (default NAT-less setup), referencing an external/pre-existing VPC whose `publicSubnets` array was not provided to the Cluster, or forgetting to add public subnets after enabling `public: true` on a previously private task.

Related errors


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