Skip to content

Storage deploy fails with 'Policy resource was already managed by another stack' after CFN enforcement change (Jan 2026) #14961

Description

@svidgen

Description

As of January 30, 2026, CloudFormation enforces single-stack ownership of IAM inline policies. This breaks amplify push for Gen1 projects with multiple environments that share storage resources targeting the same IAM role (e.g., when using imported Identity Pool/auth roles).

The deploy fails with:

The following resource(s) failed to update: [S3AuthUploadPolicy, S3AuthPublicPolicy, S3AuthProtectedPolicy, S3AuthReadPolicy, S3AuthPrivatePolicy]

Policy resource was already managed by another stack or another resource in the current stack. Found stacks: [amplify-<app>-<env2>-storage...|S3AuthPrivatePolicy]

Root Cause

When amplify env add creates a new environment, it copies cli-inputs.json verbatim — including the policyUUID field. This UUID is generated once (in s3-defaults.ts via buildShortUUID()) when storage is first added to the project. All environments therefore produce identical policy names (e.g., Private_policy_ad0f22e8).

This only becomes a problem when both conditions are met:

  1. Same PolicyName — guaranteed by the shared policyUUID across envs
  2. Same target IAM role — occurs when environments share auth roles (e.g., imported Identity Pool with shared authenticated/unauthenticated roles, or manually configured shared roles)

In the common case where each environment has its own auth roles (the default for amplify add auth), the identical policy names land on different roles, and CFN does not conflict. This is why relatively few customers hit it — it requires a shared-role configuration.

Affected Code

  • packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/s3-stack-transform.ts (lines 115-121) — policy names use policyUUID without envName differentiation
  • amplify env add clones cli-inputs.json (containing policyUUID) to new environments unchanged

Workaround

Use amplify override storage in each affected environment to make policy names unique:

// override.ts
import { AmplifyS3ResourceTemplate } from "@aws-amplify/cli-extensibility-helper";

export function override(resources: AmplifyS3ResourceTemplate) {
  const envName = "YOUR_ENV_NAME"; // e.g., "dev", "prod"
  resources.s3AuthPrivatePolicy.policyName += `-${envName}`;
  resources.s3AuthProtectedPolicy.policyName += `-${envName}`;
  resources.s3AuthPublicPolicy.policyName += `-${envName}`;
  resources.s3AuthReadPolicy.policyName += `-${envName}`;
  resources.s3AuthUploadPolicy.policyName += `-${envName}`;
}

Then run amplify push. Repeat for each environment with a different envName value.

Suggested Fix

Append the environment name to the policyUUID when generating CFN parameters in s3-stack-transform.ts:

// Before:
this.cfnInputParams.s3PrivatePolicy = `Private_policy_${userInput.policyUUID}`;

// After:
this.cfnInputParams.s3PrivatePolicy = `Private_policy_${userInput.policyUUID}_${envName}`;

This prevents new occurrences. Existing affected stacks still need the override workaround above.

Related

Environment

  • Amplify CLI: current (latest on dev)
  • Trigger: CFN enforcement change Jan 30, 2026
  • Frequency: Low — only affects projects with shared auth roles across environments (imported Identity Pool or manual role configuration)

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions