Skip to content

Commit cb985ba

Browse files
fix(aspects): "localAspects is not iterable" error (#32647)
Closes #32470 ### Reason for this change Some customers have reported seeing the error `TypeError: localAspects is not iterable` upon upgrading to CDK v2.172.0 (this is when the Priority-ordered aspects feature was released). This is likely caused by customers having dependencies on third-party constructs/libraries which are using outdated versions (< 2.172.0) of CDK. The problem more specifically is that the `Aspects.applied` function was added in v2.172.0, and the new `invokeAspects` function calls this function on all nodes in the tree. ### Description of changes Created a workaround for customers. Added the `getAspectApplications` function in `synthesis.ts` - this function creates `AspectApplication` objects from `Aspects.all` if `Aspects.applied` does not exist. ### Describe any new or updated permissions being added None. ### Description of how you validated changes New unit test in `aspect.test.ts` with a monkey patched `Aspects.applied` function. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 0150854 commit cb985ba

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

packages/aws-cdk-lib/core/lib/private/synthesis.ts

+18-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { CloudAssembly } from '../../../cx-api';
88
import * as cxapi from '../../../cx-api';
99
import { Annotations } from '../annotations';
1010
import { App } from '../app';
11-
import { AspectApplication, Aspects } from '../aspect';
11+
import { AspectApplication, AspectPriority, Aspects } from '../aspect';
1212
import { FileSystem } from '../fs';
1313
import { Stack } from '../stack';
1414
import { ISynthesisSession } from '../stack-synthesizers/types';
@@ -228,7 +228,7 @@ function invokeAspects(root: IConstruct) {
228228
const node = construct.node;
229229
const aspects = Aspects.of(construct);
230230

231-
let localAspects = aspects.applied;
231+
let localAspects = getAspectApplications(construct);
232232
const allAspectsHere = sortAspectsByPriority(inheritedAspects, localAspects);
233233

234234
const nodeAspectsCount = aspects.all.length;
@@ -290,11 +290,10 @@ function invokeAspectsV2(root: IConstruct) {
290290

291291
function recurse(construct: IConstruct, inheritedAspects: AspectApplication[]): boolean {
292292
const node = construct.node;
293-
const aspects = Aspects.of(construct);
294293

295294
let didSomething = false;
296295

297-
let localAspects = aspects.applied;
296+
let localAspects = getAspectApplications(construct);
298297
const allAspectsHere = sortAspectsByPriority(inheritedAspects, localAspects);
299298

300299
for (const aspectApplication of allAspectsHere) {
@@ -354,6 +353,21 @@ function sortAspectsByPriority(inheritedAspects: AspectApplication[], localAspec
354353
return allAspects;
355354
}
356355

356+
/**
357+
* Helper function to get aspect applications.
358+
* If `Aspects.applied` is available, it is used; otherwise, create AspectApplications from `Aspects.all`.
359+
*/
360+
function getAspectApplications(node: IConstruct): AspectApplication[] {
361+
const aspects = Aspects.of(node);
362+
if (aspects.applied !== undefined) {
363+
return aspects.applied;
364+
}
365+
366+
// Fallback: Create AspectApplications from `aspects.all`
367+
const typedAspects = aspects as Aspects;
368+
return typedAspects.all.map(aspect => new AspectApplication(node, aspect, AspectPriority.DEFAULT));
369+
}
370+
357371
/**
358372
* Find all stacks and add Metadata Resources to all of them
359373
*

packages/aws-cdk-lib/core/test/aspect.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,24 @@ describe('aspect', () => {
309309
}
310310
}
311311
}
312+
313+
test.each([
314+
{ stabilization: true },
315+
{ stabilization: false },
316+
])('Error is not thrown if Aspects.applied does not exist (stabilization: $stabilization)', ({ stabilization }) => {
317+
const app = new App({ context: { '@aws-cdk/core:aspectStabilization': stabilization } });
318+
const root = new Stack(app, 'My-Stack');
319+
320+
Aspects.of(root).add(new Tag('AspectA', 'Visited'));
321+
322+
// "Monkey patching" - Override `applied` to simulate its absence
323+
Object.defineProperty(Aspects.prototype, 'applied', {
324+
value: undefined,
325+
configurable: true,
326+
});
327+
328+
expect(() => {
329+
app.synth();
330+
}).not.toThrow();
331+
});
312332
});

0 commit comments

Comments
 (0)