Repository: aws/aws-cdk
Pull request #33875: fix: context provider's `ignoreErrorOnMissingContext` parameter is misleading
Author: login: rix0rrr
Labels: name: p2
name: contribution/core
description: This is a PR that came from AWS.
name: pr-linter/exempt-test
description: The PR linter will not require test changes
name: pr-linter/exempt-integ-test
description: The PR linter will not require integ test changes
name: pr-linter/exempt-codecov
description: The PR linter will not require codecov checks to pass
Created: 2025-03-22T14:48:44Z | Merged: 2025-03-25T11:33:28Z

In `ContextProvider.getValue()`, `ignoreErrorOnMissingContext` is a request to the CLI's context provider to not fail the lookup, but return the dummy value instead.

The operation doesn't have anything to do with missing context, and missing context isn't an error. Deprecate that parameter and add `mustExist` instead (with reversed semantics).

Also explain the `dummyValue` field and this one a bit better.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*



Diff:
diff --git a/packages/aws-cdk-lib/aws-kms/lib/key.ts b/packages/aws-cdk-lib/aws-kms/lib/key.ts
index f8c9b59961ad0..ac6da4b4d09bf 100644
--- a/packages/aws-cdk-lib/aws-kms/lib/key.ts
+++ b/packages/aws-cdk-lib/aws-kms/lib/key.ts
@@ -741,7 +741,7 @@ export class Key extends KeyBase {
       dummyValue: {
         keyId: Key.DEFAULT_DUMMY_KEY_ID,
       },
-      ignoreErrorOnMissingContext: options.returnDummyKeyOnMissing,
+      mustExist: !options.returnDummyKeyOnMissing,
     }).value;
 
     return new Import(attributes.keyId,
diff --git a/packages/aws-cdk-lib/aws-ssm/lib/parameter.ts b/packages/aws-cdk-lib/aws-ssm/lib/parameter.ts
index a7cbb96283f89..778a4beb921c1 100644
--- a/packages/aws-cdk-lib/aws-ssm/lib/parameter.ts
+++ b/packages/aws-cdk-lib/aws-ssm/lib/parameter.ts
@@ -585,7 +585,7 @@ export class StringParameter extends ParameterBase implements IStringParameter {
       provider: cxschema.ContextProvider.SSM_PARAMETER_PROVIDER,
       props: { parameterName },
       dummyValue: defaultValue || `dummy-value-for-${parameterName}`,
-      ignoreErrorOnMissingContext: defaultValue !== undefined,
+      mustExist: defaultValue === undefined,
     }).value;
 
     return value;
diff --git a/packages/aws-cdk-lib/core/lib/context-provider.ts b/packages/aws-cdk-lib/core/lib/context-provider.ts
index b58405098174b..81ea9d9227cde 100644
--- a/packages/aws-cdk-lib/core/lib/context-provider.ts
+++ b/packages/aws-cdk-lib/core/lib/context-provider.ts
@@ -30,16 +30,70 @@ export interface GetContextKeyOptions {
  */
 export interface GetContextValueOptions extends GetContextKeyOptions {
   /**
-   * The value to return if the context value was not found and a missing
-   * context is reported.
+   * The value to return if the lookup has not yet been performed.
+   *
+   * Upon first synthesis, the lookups has not yet been performed. The
+   * `getValue()` operation returns this value instead, so that synthesis can
+   * proceed. After synthesis completes the first time, the actual lookup will
+   * be performed and synthesis will run again with the *real* value.
+   *
+   * Dummy values should preferably have valid shapes so that downstream
+   * consumers of lookup values don't throw validation exceptions if they
+   * encounter a dummy value (or all possible downstream consumers need to
+   * effectively check for the well-known shape of the dummy value); throwing an
+   * exception would error out the synthesis operation and prevent the lookup
+   * and the second, real, synthesis from happening.
+   *
+   * ## Connection to mustExist
+   *
+   * `dummyValue` is also used as the official value to return if the lookup has
+   * failed and `mustExist == false`.
    */
   readonly dummyValue: any;
 
   /**
-   * When True, the context provider will not throw an error if missing context
-   * is reported
+   * Whether the resource must exist
+   *
+   * If this is set (the default), the query fails if the value or resource we
+   * tried to look up doesn't exist.
+   *
+   * If this is `false` and the value we tried to look up could not be found, the
+   * failure is suppressed and `dummyValue` is officially returned instead.
+   *
+   * When this happens, `dummyValue` is encoded into cached context and it will
+   * never be refreshed anymore until the user runs `cdk context --reset <key>`.
+   *
+   * Note that it is not possible for the CDK app code to make a distinction
+   * between "the lookup has not been performed yet" and "the lookup didn't
+   * find anything and we returned a default value instead".
+   *
+   * ## Context providers
+   *
+   * This feature must explicitly be supported by context providers. It is
+   * currently supported by:
+   *
+   * - KMS key provider
+   * - SSM parameter provider
+   *
+   * ## Note to implementors
+   *
+   * The dummy value should not be returned for all SDK lookup failures. For
+   * example, "no network" or "no credentials" or "malformed query" should
+   * not lead to the dummy value being returned. Only the case of "no such
+   * resource" should.
+   *
+   * @default true
+   */
+  readonly mustExist?: boolean;
+
+  /**
+   * Ignore a lookup failure and return the `dummyValue` instead
+   *
+   * `mustExist` is the recommended alias for this deprecated
+   * property (note that its value is reversed).
    *
    * @default false
+   * @deprecated Use mustExist instead
    */
   readonly ignoreErrorOnMissingContext?: boolean;
 }
@@ -92,6 +146,10 @@ export class ContextProvider {
   }
 
   public static getValue(scope: Construct, options: GetContextValueOptions): GetContextValueResult {
+    if ((options.mustExist !== undefined) && (options.ignoreErrorOnMissingContext !== undefined)) {
+      throw new Error('Only supply one of \'mustExist\' and \'ignoreErrorOnMissingContext\'');
+    }
+
     const stack = Stack.of(scope);
 
     if (Token.isUnresolved(stack.account) || Token.isUnresolved(stack.region)) {
@@ -108,10 +166,19 @@ export class ContextProvider {
     // if context is missing or an error occurred during context retrieval,
     // report and return a dummy value.
     if (value === undefined || providerError !== undefined) {
+      // Render 'ignoreErrorOnMissingContext' iff one of the parameters is supplied.
+      const ignoreErrorOnMissingContext = options.mustExist !== undefined || options.ignoreErrorOnMissingContext !== undefined
+        ? (options.mustExist !== undefined ? !options.mustExist : options.ignoreErrorOnMissingContext)
+        : undefined;
+
       // build a version of the props which includes the dummyValue and ignoreError flag
       const extendedProps: { [p: string]: any } = {
         dummyValue: options.dummyValue,
-        ignoreErrorOnMissingContext: options.ignoreErrorOnMissingContext,
+
+        // Even though we renamed the user-facing property, the field in the
+        // cloud assembly still has the original name, which is somewhat wrong
+        // because it's not about missing context.
+        ignoreErrorOnMissingContext,
         ...props,
       };
 


Reviews:
user: login: aws-cdk-automation
body: (This review is outdated)
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-03-22T14:50:28Z
user: login: go-to-k
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-22T19:26:15Z
user: login: rix0rrr
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T08:59:22Z
user: login: mrgrain
body: `ignoreFailedLookup `

vs.

> The dummy value should not be returned for all SDK lookup failures. For example, "no network" or "no credentials" or "malformed query" should not lead to the dummy value being returned. Only the case of "no such resource" should.`

Why not call it `ignoreResourceNotFound` (or similar) then?

And then because `ignore` always implies you know what the standard behavior is, we might be better off calling it `failOnResourceNotFound` (with a value defaulting to `true`). Or even something like `mustReturnResource`.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T11:19:52Z
user: login: mrgrain
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T18:48:04Z
user: login: mrgrain
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T18:49:39Z

Review comments:
diff_hunk: @@ -30,16 +30,66 @@ export interface GetContextKeyOptions {
  */
 export interface GetContextValueOptions extends GetContextKeyOptions {
   /**
-   * The value to return if the context value was not found and a missing
-   * context is reported.
+   * The value to return if the lookup has not yet been performed.
+   *
+   * Upon first synthesis, the lookups has not yet been performed. The
+   * `getValue()` operation returns this value instead, so that synthesis can
+   * proceed. After synthesis completes the first time, the actual lookup will
+   * be performed and synthesis will run again with the *real* value.
+   *
+   * Dummy values should preferably have valid shapes so that downstream
+   * consumers of lookup values don't throw validation exceptions if they
+   * encounter a dummy value (or all possible downstream consumers need to
+   * effectively check for the well-known shape of the dummy value); throwing an
+   * exception would error out the synthesis operation and prevent the lookup
+   * and the second, real, synthesis from happening.
+   *
+   * ## Link to ignoreErrorOnMissingContext
+   *
+   * `dummyValue` is also used as the official value to return if the lookup has
+   * failed and `ignoreErrorOnMissingContext` is set.
path: packages/aws-cdk-lib/core/lib/context-provider.ts
user: login: go-to-k
body: Isn't this ignoreFailedLookup instead of ignoreErrorOnMissingContext?

```suggestion
   * ## Link to ignoreFailedLookup
   *
   * `dummyValue` is also used as the official value to return if the lookup has
   * failed and `ignoreFailedLookup` is set.
```
created_at: 2025-03-22T19:26:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,16 +30,66 @@ export interface GetContextKeyOptions {
  */
 export interface GetContextValueOptions extends GetContextKeyOptions {
   /**
-   * The value to return if the context value was not found and a missing
-   * context is reported.
+   * The value to return if the lookup has not yet been performed.
+   *
+   * Upon first synthesis, the lookups has not yet been performed. The
+   * `getValue()` operation returns this value instead, so that synthesis can
+   * proceed. After synthesis completes the first time, the actual lookup will
+   * be performed and synthesis will run again with the *real* value.
+   *
+   * Dummy values should preferably have valid shapes so that downstream
+   * consumers of lookup values don't throw validation exceptions if they
+   * encounter a dummy value (or all possible downstream consumers need to
+   * effectively check for the well-known shape of the dummy value); throwing an
+   * exception would error out the synthesis operation and prevent the lookup
+   * and the second, real, synthesis from happening.
+   *
+   * ## Link to ignoreErrorOnMissingContext
+   *
+   * `dummyValue` is also used as the official value to return if the lookup has
+   * failed and `ignoreErrorOnMissingContext` is set.
path: packages/aws-cdk-lib/core/lib/context-provider.ts
user: login: rix0rrr
body: Of course, I decided to rename it later. Thanks!
created_at: 2025-03-24T08:59:21Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-22T15:04:46Z
body: ## [Codecov](https://app.codecov.io/gh/aws/aws-cdk/pull/33875?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) Report
Attention: Patch coverage is `0%` with `3 lines` in your changes missing coverage. Please review.
> Project coverage is 82.35%. Comparing base [(`7f2ed96`)](https://app.codecov.io/gh/aws/aws-cdk/commit/7f2ed96a5d5652dd9f03c416b4041b62d645088b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) to head [(`d46b51d`)](https://app.codecov.io/gh/aws/aws-cdk/commit/d46b51d7d1e108008042a3d4c2a2c8a3b62857fa?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws).

:x: Your patch check has failed because the patch coverage (0.00%) is below the target coverage (95.00%). You can increase the patch coverage or adjust the [target](https://docs.codecov.com/docs/commit-status#target) coverage.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main   #33875      +/-   ##
==========================================
- Coverage   82.38%   82.35%   -0.04%     
==========================================
  Files         120      120              
  Lines        6938     6941       +3     
  Branches     1170     1172       +2     
==========================================
  Hits         5716     5716              
- Misses       1119     1120       +1     
- Partials      103      105       +2     
```

| [Flag](https://app.codecov.io/gh/aws/aws-cdk/pull/33875/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) | Coverage Δ | |
|---|---|---|
| [suite.unit](https://app.codecov.io/gh/aws/aws-cdk/pull/33875/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) | `82.35% <0.00%> (-0.04%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Components](https://app.codecov.io/gh/aws/aws-cdk/pull/33875/components?src=pr&el=components&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) | Coverage Δ | |
|---|---|---|
| [packages/aws-cdk](https://app.codecov.io/gh/aws/aws-cdk/pull/33875/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) | `∅ <ø> (∅)` | |
| [packages/aws-cdk-lib/core](https://app.codecov.io/gh/aws/aws-cdk/pull/33875/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aws) | `82.35% <0.00%> (-0.04%)` | :arrow_down: |

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: rix0rrr
created_at: 2025-03-24T18:44:34Z
body: How about `mustExist` ?
author_association: CONTRIBUTOR
user: login: mergify[bot]
created_at: 2025-03-25T10:58:54Z
body: Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to [allow changes to be pushed to your fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork)).
author_association: CONTRIBUTOR
user: login: aws-cdk-automation
created_at: 2025-03-25T11:33:05Z
body: 
### AWS CodeBuild CI Report

* CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
* Commit ID: d46b51d7d1e108008042a3d4c2a2c8a3b62857fa
* Result: SUCCEEDED
* [Build Logs](https://2cl995f30a.execute-api.us-east-1.amazonaws.com/Prod/buildlogs?key=46ff78c4-a059-4e84-976e-5dd533431753%2Fbuild.log) (available for 30 days)

*Powered by [github-codebuild-logs](https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:277187709615:applications~github-codebuild-logs), available on the [AWS Serverless Application Repository](https://aws.amazon.com/serverless/serverlessrepo/)*


<!--
CREATED BY GITHUB-CODEBUILD-LOGS
-->


author_association: COLLABORATOR
user: login: mergify[bot]
created_at: 2025-03-25T11:33:25Z
body: Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to [allow changes to be pushed to your fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork)).
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-25T11:33:41Z
body: Comments on closed issues and PRs are hard for our team to see. 
If you need help, please open a new issue that references this one.
author_association: CONTRIBUTOR