Summary
This library reaches into aws-cdk-lib's private Function.environment field — and, since v4.0.0, into the private .map backing store of the internal Box that field now holds. The code's own comments admit it: "AWS does not expose the environment field" and "cast to any to access the private environment fields." It does so anyway.
That is the whole bug. A routine, semver-compatible aws-cdk-lib minor (2.252 → 2.253) changed the field's internal shape and broke cdk synth for every stack using the default sourceCodeIntegration (#596). The v4.0.0 "fix" did not remove the illegal access — it re-pointed it at the deeper new internal and raised the peer floor, then closed the follow-on breakage as the user's fault (#606). It will break again on the next refactor.
The defect (current main)
src/env.ts#L67 and #L124:
lam.environment.map.get(DD_TAGS)?.value // setGitEnvironmentVariables
lam_with_env_vars.environment.map.get(envVar) // applyEnvVariables
environment is and always has been private. aws-cdk-lib's public contract for env vars is Function.addEnvironment(key, value) — which this library already uses to write. The breakage exists only because it also reads across the private boundary.
| aws-cdk-lib |
Function.environment |
| ≤ 2.252.0 |
private environment: { [key]: EnvironmentConfig } = {}; |
| ≥ 2.253.0 |
private readonly environment: IMapBox<…> = Box.fromMap(new Map()); |
(Verified at aws-cdk tags v2.252.0 / v2.253.0.)
The correct fix
- Respect the interface. Stop reading the private field. This library is the sole writer of
DD_TAGS and the DD_* defaults on these paths, so it can track its own writes (a WeakMap<Function, …>) instead of interrogating aws-cdk-lib's private state.
- Extend the interface, properly. For the one case that benefits from reading user-set values, aws-cdk-lib has no public accessor yet — but it is open source and accepts contributions (aws/aws-cdk). Adding a supported
hasEnvironment(key) / read-only getter is a small, routine, mergeable PR. The right path was always: collaborate upstream to add the public API, then depend on it. Reaching into Box.map instead — and, when that broke, reaching in further rather than opening that PR — reflects either a lack of diligence or a lack of competence, not a genuine constraint. There was a correct option available the entire time and it was not taken.
Affected versions
Repro / impact
sourceCodeIntegration is on by default, so a transitive aws-cdk-lib bump to 2.253.0 turned cdk synth into a hard failure for downstream stacks (≤3.12.0):
TypeError: Cannot read properties of undefined (reading 'value')
at setGitEnvironmentVariables (env.js)
at DatadogLambda.addLambdaFunctions (datadog-lambda.js)
The only workarounds were disabling a default Datadog feature or pinning aws-cdk-lib. v4.0.0 converted this into a permanent peer constraint and a recurring fragility. Removing the dependency on private internals eliminates the entire class of failure.
This is also being raised with our Datadog account team. For a library published under the Datadog name that instruments production fleets by default, depending on a dependency's private internals — when a supported public path exists and a clean upstream extension was available — is below the standard we expect. We're asking for the root-cause fix, not another patch that re-points the same illegal access.
Summary
This library reaches into
aws-cdk-lib's privateFunction.environmentfield — and, since v4.0.0, into the private.mapbacking store of the internalBoxthat field now holds. The code's own comments admit it: "AWS does not expose theenvironmentfield" and "cast to any to access the private environment fields." It does so anyway.That is the whole bug. A routine, semver-compatible aws-cdk-lib minor (2.252 → 2.253) changed the field's internal shape and broke
cdk synthfor every stack using the defaultsourceCodeIntegration(#596). The v4.0.0 "fix" did not remove the illegal access — it re-pointed it at the deeper new internal and raised the peer floor, then closed the follow-on breakage as the user's fault (#606). It will break again on the next refactor.The defect (current
main)src/env.ts#L67and#L124:environmentis and always has beenprivate. aws-cdk-lib's public contract for env vars isFunction.addEnvironment(key, value)— which this library already uses to write. The breakage exists only because it also reads across the private boundary.Function.environmentprivate environment: { [key]: EnvironmentConfig } = {};private readonly environment: IMapBox<…> = Box.fromMap(new Map());(Verified at aws-cdk tags
v2.252.0/v2.253.0.)The correct fix
DD_TAGSand theDD_*defaults on these paths, so it can track its own writes (aWeakMap<Function, …>) instead of interrogating aws-cdk-lib's private state.hasEnvironment(key)/ read-only getter is a small, routine, mergeable PR. The right path was always: collaborate upstream to add the public API, then depend on it. Reaching intoBox.mapinstead — and, when that broke, reaching in further rather than opening that PR — reflects either a lack of diligence or a lack of competence, not a genuine constraint. There was a correct option available the entire time and it was not taken.Affected versions
Repro / impact
sourceCodeIntegrationis on by default, so a transitive aws-cdk-lib bump to 2.253.0 turnedcdk synthinto a hard failure for downstream stacks (≤3.12.0):The only workarounds were disabling a default Datadog feature or pinning aws-cdk-lib. v4.0.0 converted this into a permanent peer constraint and a recurring fragility. Removing the dependency on private internals eliminates the entire class of failure.
This is also being raised with our Datadog account team. For a library published under the Datadog name that instruments production fleets by default, depending on a dependency's private internals — when a supported public path exists and a clean upstream extension was available — is below the standard we expect. We're asking for the root-cause fix, not another patch that re-points the same illegal access.