anomalyco/sst · error · VisibleError

Lifecycle rule at index ${index} has an empty or whitespace-

Error message

Lifecycle rule at index ${index} has an empty or whitespace-only "id". Please provide a valid id or omit it to use the auto-generated id.

What it means

S3 lifecycle rule IDs must be non-empty, and SST additionally rejects whitespace-only IDs. When a lifecycle rule's `id` trims to an empty string, SST throws this VisibleError because S3 would reject it and auto-generated IDs are the intended default. Omitting `id` entirely lets SST generate `${name}LifecycleRule${index}`.

Source

Thrown at platform/src/components/aws/bucket.ts:971

            },
            { parent },
          ),
        );
      });
    }

    function createLifecycle() {
      return output(args.lifecycle).apply((lifecycleRules) => {
        if (!lifecycleRules || lifecycleRules.length === 0) return;

        const seenIds = new Map<string, number>();

        const resolvedIds = lifecycleRules.map((rule, index) => {
          const rawId = rule.id ?? `${name}LifecycleRule${index}`;
          const resolvedId = rawId.trim();

          if (resolvedId.length === 0) {
            throw new VisibleError(
              `Lifecycle rule at index ${index} has an empty or whitespace-only "id". Please provide a valid id or omit it to use the auto-generated id.`,
            );
          }

          if (resolvedId.length > 255) {
            throw new VisibleError(
              `Lifecycle rule at index ${index} has an "id" that is ${resolvedId.length} characters long. AWS S3 lifecycle rule IDs cannot exceed 255 characters.`,
            );
          }

          const existingIndex = seenIds.get(resolvedId);
          if (existingIndex !== undefined) {
            throw new VisibleError(
              `Lifecycle rule "id" values must be unique. The id "${resolvedId}" is used by rules at indexes ${existingIndex} and ${index}.`,
            );
          }
          seenIds.set(resolvedId, index);

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Omit the `id` field so SST auto-generates a valid ID
  2. Provide a meaningful non-empty, non-whitespace id for the rule
  3. Validate/trim the id source (env var, config) upstream and fall back to omitting it when empty

Example fix

// before
transform: {
  bucket: { lifecycleRules: [{ id: "", status: "Enabled", expiration: { days: 30 } }] }
}
// after
transform: {
  bucket: { lifecycleRules: [{ status: "Enabled", expiration: { days: 30 } }] }
}
Defensive patterns

Strategy: validation

Validate before calling

rules.forEach((r, i) => {
  if (r.id != null && r.id.trim() === "") {
    delete r.id; // fall back to auto-generated id
  }
});

Type guard

function hasValidLifecycleId(r: { id?: string }): boolean {
  return r.id === undefined || r.id.trim().length > 0;
}

Try / catch

try {
  new sst.aws.Bucket("B", { transform: { bucket: { lifecycleRules: rules } } });
} catch (e) {
  if ((e as Error).message.includes("empty or whitespace-only")) {
    console.error("Fix or drop the empty lifecycle rule id");
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a lifecycle rule in `bucket.transform` or lifecycle args with `id: ""` or `id: " "` (whitespace only).

Common situations: Setting `id` from an env var or user config that is blank; building rule objects programmatically with an uninitialized id field; trimming user input without checking emptiness before assigning.

Related errors


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