@go-to-k/cdkd 0.290.22 → 0.290.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
- import { $ as secretBearing, $i as normalizeAwsError, $n as scrubResourceRecord, $r as synthesisStatusMessage, $t as s3BucketArn, A as extractDeploymentEventError, An as repairMalformedResourcesForReadOnly, Ar as isCrossRegionRedirect, At as isImpossibleEmptyStoredAttribute, B as toCfnInteger, Bn as TEMPLATE_SOURCED_RULES, Br as describeDockerFailure, Bt as coerceCfnBoolean, C as buildFinalSnapshotIdentifier, Ci as processStackMessages, Cn as refuseMalformedOutputs, Cr as loadPublishableAssetManifest, Ct as isTerminationProtectionPropagationError, D as refusesFinalSnapshot, Di as getAwsClients, Dn as refuseMalformedState, Dr as assertAssetBucketRegion, Dt as cfnRefValueFromPhysicalId, E as isFinalSnapshotError, Ei as AwsClients, En as refuseMalformedResourcesForDestroy, Er as BOOTSTRAP_MARKER_PREFIX, Et as carriesFetchableDynamicReference, F as isStatefulRecreateTargetSync, Fi as DeployCancelledError, Fn as DagBuilder, Fr as buildDenyExternalAccessPolicy, Ft as isSettledInstanceState, G as gray, Gi as ResourceTimeoutError, Gn as identityKeyFor, Gr as redactDockerArgvValues, Gt as readConfigString, H as formatResourceLine, Hi as NestedStackChildDirectDestroyError, Hn as createSecretMasker, Hr as formatDockerLoginError, Ht as configBooleanRefusal, I as renderStatefulReason, Ii as DynamicReferenceRegionAmbiguousError, In as TemplateParser, Ir as describeAwsFailure, It as WAFv2WebACLProvider, J as yellow, Ji as StackTerminationProtectionError, Jn as maskSecretsInError, Jr as escapeRegExp, Jt as requireConfigObject, K as green, Ki as ResourceUpdateNotSupportedError, Kn as isSingleDynamicReferenceToken, Kr as runDockerForeground, Kt as replayWarn, L as WARM_THROUGHPUT_MEMBERS, Li as IntrinsicResolutionRefusalError, Ln as STATE_SOURCED_BASELINE_RULES, Lr as buildDockerImage, Lt as normalizeAwsTagsToCfn, M as planOrphanAdoption, Mn as findSilentDropProperties, Mr as readBootstrapMarkerBody, Mt as isUnboundTemplateParameter, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ni as CrossAccountSecretRefusalError, Nn as describeTypeWithThrottleRetry, Nr as validateAssetBucketName, Nt as parameterTypeMayLoseSecretIdentity, O as unsupportedFinalSnapshotError, Oi as resetAwsClients, On as repairMalformedOutputsForReadOnly, Or as ensureAssetStorage, Ot as coerceParameterTypedValue, P as isStatefulRecreateTargetForReplace, Pn as withRetry, Pr as validateContainerRepoName, Pt as refStateLookupFromResource, Q as isExportAliasCollision, Qn as redactSecretsForState, Qr as Synthesizer, Qt as withSharedDrainBudget, R as coerceWarmThroughput$1, Ri as LocalInvokeBuildError$1, Rn as STATE_SOURCED_CROSS_GENERATION_RULES, Rr as describeDockerCapturedOutput, Rt as resolveExplicitPhysicalId, S as PRE_DELETE_SNAPSHOT_TYPES, Si as AssemblyReader, Sn as refuseMalformedNestedChildOutputs, Sr as createAssetRedirectResolver, St as disableInstanceApiTermination, T as createPreDeleteFinalSnapshot, Ti as resolveBucketRegion, Tn as refuseMalformedResourcePropertiesForOrphan, Tr as AssetModeResolver, Tt as carriesDynamicReference, U as bold, Ui as PartialFailureError, Un as dynamicReferenceTokens, Ur as getDockerCmd, Ut as configIntegerRefusal, V as toFiniteNumber, Vi as MalformedProducerRecordRefusalError, Vn as carriesSecretMask, Vr as dockerSpawnEnvWithSensitive, Vt as coerceCfnInteger, W as cyan, Wi as ProvisioningError, Wn as errorCauseChain, Wr as partitionSensitiveEnv, Wt as configStringRefusal, X as collectPublishedOutputNames, Xn as recordMaskOnlyValue, Xr as AssetManifestLoader, Xt as classifyReplaySecretRegion, Y as collectDeclaredOutputNames, Yn as maskSecretsInText, Yr as stripControlChars, Yt as requireConfigString, Z as exportAliasCollisionScrubWarning, Zn as recoverMaskedOutput, Zr as getDockerImageBySourceHash, Zt as producerRegionsFromState, _ as isSecretBearingReferenceString, _i as decodeListingKey, _n as malformedRenderedContainersWarning, _r as shouldRetainResource, _t as isWaitAbandonedError, a as DeploymentEventsStore, aa as markNonRetryable, ai as resolveSkipPrefix, an as applyCallerIdentityCredentials, ar as forceQuitRecoveryClause, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bi as canonicalizeRegion, bn as malformedStateRefusalMessage, br as WorkGraph, bt as deleteIndeterminateGuards, c as replayFailedOperations, ci as resolveUseCdkBootstrapAssets, cn as INTRINSIC_KEYS, cr as CUSTOM_RESOURCE_RESPONSE_PREFIX, ct as createMaskedRetryLogger, d as updatePartialReason, di as CFN_TEMPLATE_BODY_LIMIT, dn as hasReadableResources, dr as hasReadableExportSet, dt as beginCommandInterruptScope, ea as withErrorHandling, ei as getDefaultStateBucketName, en as s3BucketDomainName, er as LockManager, et as secretBearingStateKeyWarning, f as withResourceDeadline, fi as CFN_TEMPLATE_URL_LIMIT, fn as malformedExportNamesWarning, fr as importableOutputKeys, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, gn as malformedOutputsWarning, gr as orphansCarriedFrom, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as uploadCfnTemplate, hn as malformedOutputsRefusalMessage, hr as orphansAfterRollback, ht as startInterruptWatch, i as DeploymentEventsReader, ia as isTransientServerError, ii as resolveCaptureObservedState, in as applyRoleArnIfSet, ir as buildLockContentionMessage, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, ji as CdkdError, jn as findActionableSilentDrops, jr as parseBootstrapMarker, jt as isNamelessDynamicReferenceError, k as makeCanonicalizePropertiesFn, ki as setAwsClients, kn as repairMalformedResourcePropertiesForReadOnly, kr as getBootstrapMarkerKey, kt as getAccountInfo, l as replayRollback, li as stateBucketExistenceConfirmed, ln as STATE_RESOURCES_MALFORMED, lr as DEFAULT_STATE_PREFIX, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as findLargeInlineResources, mn as malformedLocalOutputsWarning, mr as isReadableBag, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, na as isRetryableTransientError, ni as resolveApp, nn as s3BucketRegionalDomainName, nr as rebuildClientForBucketRegion, nt as getCurrentResourceSecrets, o as planFailedOps, oa as markRedactedCause, oi as resolveStateBucketWithDefault, on as callerEnvCredentials, or as formatLockExpiry, ot as ProviderRegistry, p as maskingRetryLogger, pi as MIGRATE_TMP_PREFIX, pn as malformedExportSourceWarning, pr as importableOutputs, pt as interruptWatchListenerCount, q as red, qi as StackHasActiveImportsError, qn as markSameGenerationBag, qr as runDockerStreaming, qt as requireConfigArray, r as DeployEngine, ra as isThrottlingError, ri as resolveAutoAssetStorage, rn as s3BucketWebsiteUrl, rr as buildForceUnlockCommand, rt as IAMRoleProvider, s as planRollback, sa as retryClassificationText, si as resolveStateBucketWithDefaultAndSource, sn as DiffCalculator, sr as shellQuote, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ta as isMarkedNonRetryable, ti as getLegacyStateBucketName, tn as s3BucketDualStackDomainName, tr as S3StateBackend, tt as secretSafeKeyDisplay, u as updatePartialMessage, ui as warnDeprecatedNoPrefixCliFlag, un as hasReadableOutputs, ur as exportNamesCarriedFrom, ut as maskerOrIdentity, v as keptWholeReasonText, vi as expectedOwnerParam, vn as malformedResourcePropertiesWarning, vr as AssetPublisher, vt as slowCcOperationTimeoutMs, w as ccRoutedFinalSnapshotError, wn as refuseMalformedOutputsForDestroy, wr as rewriteTemplateAssetReferences, wt as IntrinsicFunctionResolver, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xi as derivePartitionAndUrlSuffix, xn as producerRecordKey, xr as buildAssetRedirectMap, xt as deleteSkipReason, y as mergeNoChangeOutputs, yi as PARTITION_TABLE, yn as malformedResourcesWarning, yr as stringifyValue, yt as UNSPECIFIED_SKIP_REASON, z as isWarmThroughputDecrease, zi as LocalStartServiceError, zn as STATE_SOURCED_READBACK_RULES, zr as describeDockerExecFailure, zt as assertRegionMatch } from "./deploy-engine-Dbmoo4FQ.js";
2
- import { C as displaySafe, S as displayIdent, _ as withSkipPrefix, b as STACK_REF_MAX_CODE_POINTS, c as PATTERN_B_NAME_OPTIONS, f as explicitNamePropertyFor, h as getCurrentStackName, i as reserveStdoutForPayload, l as PATTERN_B_NAME_PROPERTIES, m as generateResourceNameWithFallback, n as getLogger, o as runStackBuffered, p as generateResourceName, s as getLiveRenderer, u as PATTERN_B_RESOURCE_TYPES, v as withStackName, w as truncateCodePoints, x as UNRENDERABLE } from "./logger-C17H06QA.js";
1
+ import { $ as secretBearing, $n as scrubResourceRecord, $r as Synthesizer, $t as s3BucketArn, A as extractDeploymentEventError, Ai as setAwsClients, An as repairMalformedResourcesForReadOnly, Ar as isCrossRegionRedirect, At as isImpossibleEmptyStoredAttribute, B as toCfnInteger, Bi as LocalStartServiceError, Bn as TEMPLATE_SOURCED_RULES, Br as describeDockerExecFailure, Bt as coerceCfnBoolean, C as buildFinalSnapshotIdentifier, Ci as AssemblyReader, Cn as refuseMalformedOutputs, Cr as loadPublishableAssetManifest, Ct as isTerminationProtectionPropagationError, D as refusesFinalSnapshot, Di as AwsClients, Dn as refuseMalformedState, Dr as assertAssetBucketRegion, Dt as cfnRefValueFromPhysicalId, E as isFinalSnapshotError, Ei as resolveBucketRegion, En as refuseMalformedResourcesForDestroy, Er as BOOTSTRAP_MARKER_PREFIX, Et as carriesFetchableDynamicReference, F as isStatefulRecreateTargetSync, Fn as DagBuilder, Fr as buildDenyExternalAccessPolicy, Ft as isSettledInstanceState, G as gray, Gi as ProvisioningError, Gn as identityKeyFor, Gr as partitionSensitiveEnv, Gt as readConfigString, H as formatResourceLine, Hi as MalformedProducerRecordRefusalError, Hn as createSecretMasker, Hr as dockerSpawnEnvWithSensitive, Ht as configBooleanRefusal, I as renderStatefulReason, Ii as DeployCancelledError, In as TemplateParser, Ir as describeAwsFailure, It as WAFv2WebACLProvider, J as yellow, Ji as StackHasActiveImportsError, Jn as maskSecretsInError, Jr as runDockerStreaming, Jt as requireConfigObject, K as green, Ki as ResourceTimeoutError, Kn as isSingleDynamicReferenceToken, Kr as redactDockerArgvValues, Kt as replayWarn, L as WARM_THROUGHPUT_MEMBERS, Li as DynamicReferenceRegionAmbiguousError, Ln as STATE_SOURCED_BASELINE_RULES, Lr as safeStringify, Lt as normalizeAwsTagsToCfn, M as planOrphanAdoption, Mi as CdkdError, Mn as findSilentDropProperties, Mr as readBootstrapMarkerBody, Mt as isUnboundTemplateParameter, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Nn as describeTypeWithThrottleRetry, Nr as validateAssetBucketName, Nt as parameterTypeMayLoseSecretIdentity, O as unsupportedFinalSnapshotError, Oi as getAwsClients, On as repairMalformedOutputsForReadOnly, Or as ensureAssetStorage, Ot as coerceParameterTypedValue, P as isStatefulRecreateTargetForReplace, Pi as CrossAccountSecretRefusalError, Pn as withRetry, Pr as validateContainerRepoName, Pt as refStateLookupFromResource, Q as isExportAliasCollision, Qn as redactSecretsForState, Qr as getDockerImageBySourceHash, Qt as withSharedDrainBudget, R as coerceWarmThroughput$1, Ri as IntrinsicResolutionRefusalError, Rn as STATE_SOURCED_CROSS_GENERATION_RULES, Rr as buildDockerImage, Rt as resolveExplicitPhysicalId, S as PRE_DELETE_SNAPSHOT_TYPES, Si as derivePartitionAndUrlSuffix, Sn as refuseMalformedNestedChildOutputs, Sr as createAssetRedirectResolver, St as disableInstanceApiTermination, T as createPreDeleteFinalSnapshot, Tn as refuseMalformedResourcePropertiesForOrphan, Tr as AssetModeResolver, Tt as carriesDynamicReference, U as bold, Ui as NestedStackChildDirectDestroyError, Un as dynamicReferenceTokens, Ur as formatDockerLoginError, Ut as configIntegerRefusal, V as toFiniteNumber, Vn as carriesSecretMask, Vr as describeDockerFailure, Vt as coerceCfnInteger, W as cyan, Wi as PartialFailureError, Wn as errorCauseChain, Wr as getDockerCmd, Wt as configStringRefusal, X as collectPublishedOutputNames, Xn as recordMaskOnlyValue, Xr as stripControlChars, Xt as classifyReplaySecretRegion, Y as collectDeclaredOutputNames, Yi as StackTerminationProtectionError, Yn as maskSecretsInText, Yr as escapeRegExp, Yt as requireConfigString, Z as exportAliasCollisionScrubWarning, Zn as recoverMaskedOutput, Zr as AssetManifestLoader, Zt as producerRegionsFromState, _ as isSecretBearingReferenceString, _i as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, _n as malformedRenderedContainersWarning, _r as shouldRetainResource, _t as isWaitAbandonedError, a as DeploymentEventsStore, aa as isTransientServerError, ai as resolveCaptureObservedState, an as applyCallerIdentityCredentials, ar as forceQuitRecoveryClause, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bi as PARTITION_TABLE, bn as malformedStateRefusalMessage, br as WorkGraph, bt as deleteIndeterminateGuards, c as replayFailedOperations, ca as retryClassificationText, ci as resolveStateBucketWithDefaultAndSource, cn as INTRINSIC_KEYS, cr as CUSTOM_RESOURCE_RESPONSE_PREFIX, ct as createMaskedRetryLogger, d as updatePartialReason, di as warnDeprecatedNoPrefixCliFlag, dn as hasReadableResources, dr as hasReadableExportSet, dt as beginCommandInterruptScope, ea as normalizeAwsError, ei as synthesisStatusMessage, en as s3BucketDomainName, er as LockManager, et as secretBearingStateKeyWarning, f as withResourceDeadline, fi as CFN_TEMPLATE_BODY_LIMIT, fn as malformedExportNamesWarning, fr as importableOutputKeys, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as uploadCfnTemplate, gn as malformedOutputsWarning, gr as orphansCarriedFrom, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as findLargeInlineResources, hn as malformedOutputsRefusalMessage, hr as orphansAfterRollback, ht as startInterruptWatch, i as DeploymentEventsReader, ia as isThrottlingError, ii as resolveAutoAssetStorage, in as applyRoleArnIfSet, ir as buildLockContentionMessage, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, jn as findActionableSilentDrops, jr as parseBootstrapMarker, jt as isNamelessDynamicReferenceError, k as makeCanonicalizePropertiesFn, ki as resetAwsClients, kn as repairMalformedResourcePropertiesForReadOnly, kr as getBootstrapMarkerKey, kt as getAccountInfo, l as replayRollback, li as resolveUseCdkBootstrapAssets, ln as STATE_RESOURCES_MALFORMED, lr as DEFAULT_STATE_PREFIX, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as MIGRATE_TMP_PREFIX, mn as malformedLocalOutputsWarning, mr as isReadableBag, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, na as isMarkedNonRetryable, ni as getLegacyStateBucketName, nn as s3BucketRegionalDomainName, nr as rebuildClientForBucketRegion, nt as getCurrentResourceSecrets, o as planFailedOps, oa as markNonRetryable, oi as resolveSkipPrefix, on as callerEnvCredentials, or as formatLockExpiry, ot as ProviderRegistry, p as maskingRetryLogger, pi as CFN_TEMPLATE_URL_LIMIT, pn as malformedExportSourceWarning, pr as importableOutputs, pt as interruptWatchListenerCount, q as red, qi as ResourceUpdateNotSupportedError, qn as markSameGenerationBag, qr as runDockerForeground, qt as requireConfigArray, r as DeployEngine, ra as isRetryableTransientError, ri as resolveApp, rn as s3BucketWebsiteUrl, rr as buildForceUnlockCommand, rt as IAMRoleProvider, s as planRollback, sa as markRedactedCause, si as resolveStateBucketWithDefault, sn as DiffCalculator, sr as shellQuote, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ta as withErrorHandling, ti as getDefaultStateBucketName, tn as s3BucketDualStackDomainName, tr as S3StateBackend, tt as secretSafeKeyDisplay, u as updatePartialMessage, ui as stateBucketExistenceConfirmed, un as hasReadableOutputs, ur as exportNamesCarriedFrom, ut as maskerOrIdentity, v as keptWholeReasonText, vi as decodeListingKey, vn as malformedResourcePropertiesWarning, vr as AssetPublisher, vt as slowCcOperationTimeoutMs, w as ccRoutedFinalSnapshotError, wi as processStackMessages, wn as refuseMalformedOutputsForDestroy, wr as rewriteTemplateAssetReferences, wt as IntrinsicFunctionResolver, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xi as canonicalizeRegion, xn as producerRecordKey, xr as buildAssetRedirectMap, xt as deleteSkipReason, y as mergeNoChangeOutputs, yi as expectedOwnerParam, yn as malformedResourcesWarning, yr as stringifyValue, yt as UNSPECIFIED_SKIP_REASON, z as isWarmThroughputDecrease, zi as LocalInvokeBuildError$1, zn as STATE_SOURCED_READBACK_RULES, zr as describeDockerCapturedOutput, zt as assertRegionMatch } from "./deploy-engine-BcNBidfy.js";
2
+ import { C as displaySafe, S as displayIdent, _ as withSkipPrefix, b as STACK_REF_MAX_CODE_POINTS, c as PATTERN_B_NAME_OPTIONS, f as explicitNamePropertyFor, h as getCurrentStackName, i as reserveStdoutForPayload, l as PATTERN_B_NAME_PROPERTIES, m as generateResourceNameWithFallback, n as getLogger, o as runStackBuffered, p as generateResourceName, s as getLiveRenderer, u as PATTERN_B_RESOURCE_TYPES, v as withStackName, w as truncateCodePoints, x as UNRENDERABLE } from "./logger-CkHVgzLx.js";
3
3
  import { n as awsClientDefaults } from "./aws-client-defaults-BoIxyCir.js";
4
- import { t as getCdkdVersion } from "./version-CpOEkAtB.js";
5
- import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-DTzndMHB.js";
4
+ import { t as getCdkdVersion } from "./version-PsB8OjhM.js";
5
+ import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-CHeJf5zw.js";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { createHash, randomBytes, randomUUID } from "node:crypto";
8
8
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -4777,7 +4777,7 @@ var IAMManagedPolicyProvider = class {
4777
4777
  await this.iamClient.send(new DeletePolicyCommand({ PolicyArn: policyArn }));
4778
4778
  this.logger.debug(`Cleaned up partially-created managed policy ${logicalId} (${policyArn}) after attachment failure`);
4779
4779
  } catch (cleanupError) {
4780
- this.logger.warn(`Failed to clean up partially-created managed policy ${logicalId} (${policyArn}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required: detach principals (aws iam list-entities-for-policy --policy-arn ${policyArn}), delete versions (aws iam list-policy-versions --policy-arn ${policyArn} then aws iam delete-policy-version), then aws iam delete-policy --policy-arn ${policyArn}`);
4780
+ this.logger.warn(`Failed to clean up partially-created managed policy ${logicalId} (${policyArn}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required: detach principals (aws iam list-entities-for-policy --policy-arn ${policyArn}), delete versions (aws iam list-policy-versions --policy-arn ${policyArn} then aws iam delete-policy-version), then aws iam delete-policy --policy-arn ${policyArn}`);
4781
4781
  }
4782
4782
  throw innerError;
4783
4783
  }
@@ -4811,8 +4811,8 @@ var IAMManagedPolicyProvider = class {
4811
4811
  this.logger.warn(`Skipped deleting old managed policy ${physicalId} during replacement: ${deleteResult.reason}. The old policy may be orphaned and require manual cleanup.`);
4812
4812
  }
4813
4813
  } catch (error) {
4814
- orphanReason = `old managed policy ${physicalId} could not be deleted: ${String(error)}`;
4815
- this.logger.warn(`Failed to delete old managed policy ${physicalId} during replacement: ${String(error)}. The old policy may be orphaned and require manual cleanup.`);
4814
+ orphanReason = `old managed policy ${physicalId} could not be deleted: ${safeStringify(error)}`;
4815
+ this.logger.warn(`Failed to delete old managed policy ${physicalId} during replacement: ${safeStringify(error)}. The old policy may be orphaned and require manual cleanup.`);
4816
4816
  }
4817
4817
  const base = {
4818
4818
  physicalId: createResult.physicalId,
@@ -5272,7 +5272,7 @@ var IAMInstanceProfileProvider = class {
5272
5272
  await this.iamClient.send(new DeleteInstanceProfileCommand({ InstanceProfileName: instanceProfileName }));
5273
5273
  this.logger.debug(`Cleaned up partially-created IAM instance profile ${logicalId} (${instanceProfileName}) after wiring failure`);
5274
5274
  } catch (cleanupError) {
5275
- this.logger.warn(`Failed to clean up partially-created IAM instance profile ${logicalId} (${instanceProfileName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: remove every role (aws iam remove-role-from-instance-profile --instance-profile-name ${instanceProfileName} --role-name <name>) then aws iam delete-instance-profile --instance-profile-name ${instanceProfileName}`);
5275
+ this.logger.warn(`Failed to clean up partially-created IAM instance profile ${logicalId} (${instanceProfileName}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: remove every role (aws iam remove-role-from-instance-profile --instance-profile-name ${instanceProfileName} --role-name <name>) then aws iam delete-instance-profile --instance-profile-name ${instanceProfileName}`);
5276
5276
  }
5277
5277
  throw innerError;
5278
5278
  }
@@ -5548,7 +5548,7 @@ var IAMAccessKeyProvider = class {
5548
5548
  AccessKeyId: accessKeyId
5549
5549
  }));
5550
5550
  } catch (cleanupError) {
5551
- this.logger.warn(`Failed to clean up IAM access key ${logicalId} (${accessKeyId}) minted by a partial CreateAccessKey response: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
5551
+ this.logger.warn(`Failed to clean up IAM access key ${logicalId} (${accessKeyId}) minted by a partial CreateAccessKey response: ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
5552
5552
  }
5553
5553
  throw new Error("CreateAccessKey returned no AccessKeyId/SecretAccessKey");
5554
5554
  }
@@ -5566,7 +5566,7 @@ var IAMAccessKeyProvider = class {
5566
5566
  }));
5567
5567
  this.logger.debug(`Cleaned up partially-created IAM access key ${logicalId} (${accessKeyId}) after status wiring failure`);
5568
5568
  } catch (cleanupError) {
5569
- this.logger.warn(`Failed to clean up partially-created IAM access key ${logicalId} (${accessKeyId}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
5569
+ this.logger.warn(`Failed to clean up partially-created IAM access key ${logicalId} (${accessKeyId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
5570
5570
  }
5571
5571
  throw innerError;
5572
5572
  }
@@ -5671,7 +5671,7 @@ var IAMAccessKeyProvider = class {
5671
5671
  AccessKeyId: accessKeyId
5672
5672
  }));
5673
5673
  } catch (error) {
5674
- this.logger.warn(`Failed to delete the orphaned IAM access key ${accessKeyId} for user ${userName}: ${error instanceof Error ? error.message : String(error)}. Manual deletion may be required: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
5674
+ this.logger.warn(`Failed to delete the orphaned IAM access key ${accessKeyId} for user ${userName}: ${describeAwsFailure(error).detail}. Manual deletion may be required: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
5675
5675
  }
5676
5676
  }
5677
5677
  }
@@ -5703,7 +5703,7 @@ var IAMAccessKeyProvider = class {
5703
5703
  marker = page.IsTruncated ? page.Marker : void 0;
5704
5704
  } while (marker);
5705
5705
  } catch (error) {
5706
- this.logger.warn(`Could not list existing access keys for user ${userName} while creating ${logicalId}: ${error instanceof Error ? error.message : String(error)}. Orphan detection is DISABLED for this create, so a retried attempt may leave an unusable but ACTIVE access key on the user. Grant iam:ListAccessKeys, or check the user's keys after the deploy: aws iam list-access-keys --user-name ${userName}`);
5706
+ this.logger.warn(`Could not list existing access keys for user ${userName} while creating ${logicalId}: ${describeAwsFailure(error).detail}. Orphan detection is DISABLED for this create, so a retried attempt may leave an unusable but ACTIVE access key on the user. Grant iam:ListAccessKeys, or check the user's keys after the deploy: aws iam list-access-keys --user-name ${userName}`);
5707
5707
  return;
5708
5708
  }
5709
5709
  return keys;
@@ -6015,7 +6015,7 @@ var IAMUserGroupProvider = class {
6015
6015
  await this.iamClient.send(new DeleteUserCommand({ UserName: userName }));
6016
6016
  this.logger.debug(`Cleaned up partially-created IAM user ${logicalId} (${userName}) after wiring failure`);
6017
6017
  } catch (cleanupError) {
6018
- this.logger.warn(`Failed to clean up partially-created IAM user ${logicalId} (${userName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: remove from groups, detach managed policies, delete inline policies, delete login profile (aws iam delete-login-profile --user-name ${userName}), remove permissions boundary (aws iam delete-user-permissions-boundary --user-name ${userName}), then aws iam delete-user --user-name ${userName}`);
6018
+ this.logger.warn(`Failed to clean up partially-created IAM user ${logicalId} (${userName}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: remove from groups, detach managed policies, delete inline policies, delete login profile (aws iam delete-login-profile --user-name ${userName}), remove permissions boundary (aws iam delete-user-permissions-boundary --user-name ${userName}), then aws iam delete-user --user-name ${userName}`);
6019
6019
  }
6020
6020
  throw innerError;
6021
6021
  }
@@ -6313,7 +6313,7 @@ var IAMUserGroupProvider = class {
6313
6313
  await this.iamClient.send(new DeleteGroupCommand({ GroupName: groupName }));
6314
6314
  this.logger.debug(`Cleaned up partially-created IAM group ${logicalId} (${groupName}) after wiring failure`);
6315
6315
  } catch (cleanupError) {
6316
- this.logger.warn(`Failed to clean up partially-created IAM group ${logicalId} (${groupName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: detach managed policies + delete inline policies, then aws iam delete-group --group-name ${groupName}`);
6316
+ this.logger.warn(`Failed to clean up partially-created IAM group ${logicalId} (${groupName}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: detach managed policies + delete inline policies, then aws iam delete-group --group-name ${groupName}`);
6317
6317
  }
6318
6318
  throw innerError;
6319
6319
  }
@@ -10059,7 +10059,7 @@ var S3BucketProvider = class S3BucketProvider {
10059
10059
  }
10060
10060
  return {
10061
10061
  kind: "indeterminate",
10062
- reason: probeError instanceof Error ? probeError.message : String(probeError),
10062
+ reason: describeAwsFailure(probeError).detail,
10063
10063
  errorName: probeError instanceof Error ? probeError.name : typeof probeError
10064
10064
  };
10065
10065
  }
@@ -10223,7 +10223,7 @@ var S3BucketProvider = class S3BucketProvider {
10223
10223
  await this.s3Client.send(new DeleteBucketCommand({ Bucket: bucketName }));
10224
10224
  this.logger.debug(`Cleaned up partially-created S3 bucket ${logicalId} (${bucketName}) after wiring failure`);
10225
10225
  } catch (cleanupError) {
10226
- this.logger.debug(`DeleteBucket cleanup failed for S3 bucket ${logicalId} (${bucketName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
10226
+ this.logger.debug(`DeleteBucket cleanup failed for S3 bucket ${logicalId} (${bucketName}): ${describeAwsFailure(cleanupError).detail}`);
10227
10227
  const maskSecrets = maskerOrIdentity(context?.maskSecrets);
10228
10228
  this.logger.warn(maskSecrets(`Failed to clean up partially-created S3 bucket ${logicalId} (${bucketName}) (${cleanupError instanceof Error ? cleanupError.name : typeof cleanupError}). Re-run with --verbose for AWS's own message. ` + manualBucketDeletionClause(bucketName, maskSecrets)));
10229
10229
  }
@@ -11037,7 +11037,7 @@ var S3BucketProvider = class S3BucketProvider {
11037
11037
  this.logger.debug(`Successfully deleted S3 bucket ${logicalId}`);
11038
11038
  return;
11039
11039
  } catch (error) {
11040
- const msg = error instanceof Error ? error.message : String(error);
11040
+ const msg = describeAwsFailure(error).detail;
11041
11041
  if (msg.includes("not empty") || msg.includes("BucketNotEmpty")) {
11042
11042
  if (!allowAutoEmpty) throw new Error(`bucket ${bucketName} is not empty. Matching CloudFormation, cdkd does not delete a non-empty bucket unless it opted into automatic emptying (CDK's autoDeleteObjects: true, i.e. the '${S3_AUTO_DELETE_OBJECTS_TAG}' tag). Either empty the bucket first (delete all objects — and for versioned buckets all object versions and delete markers), or redeploy with autoDeleteObjects: true and destroy again.`);
11043
11043
  this.logger.info(`Bucket ${bucketName} not empty (attempt ${attempt}/${maxAttempts}), emptying (auto-delete opt-in present)...`);
@@ -11361,7 +11361,7 @@ var S3BucketPolicyProvider = class {
11361
11361
  try {
11362
11362
  canonical = (await getAwsClients().cloudFront.send(new GetCloudFrontOriginAccessIdentityCommand({ Id: oaiId }))).CloudFrontOriginAccessIdentity?.S3CanonicalUserId ?? null;
11363
11363
  } catch (err) {
11364
- this.logger.debug(`Could not resolve CloudFront OAI ${oaiId} canonical user id for bucket-policy drift normalization: ${err instanceof Error ? err.message : String(err)} — leaving the principal unchanged.`);
11364
+ this.logger.debug(`Could not resolve CloudFront OAI ${oaiId} canonical user id for bucket-policy drift normalization: ${describeAwsFailure(err).detail} — leaving the principal unchanged.`);
11365
11365
  canonical = null;
11366
11366
  }
11367
11367
  oaiCanonicalUserIdCache.set(oaiId, canonical);
@@ -12244,7 +12244,7 @@ var SNSTopicProvider = class {
12244
12244
  await this.snsClient.send(new DeleteTopicCommand({ TopicArn: topicArn }));
12245
12245
  this.logger.debug(`Cleaned up partially-created SNS topic ${logicalId} (${topicArn}) after wiring failure`);
12246
12246
  } catch (cleanupError) {
12247
- warn(`Failed to clean up partially-created SNS topic ${logicalId} (${topicArn}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws sns delete-topic --topic-arn ${topicArn}`);
12247
+ warn(`Failed to clean up partially-created SNS topic ${logicalId} (${topicArn}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws sns delete-topic --topic-arn ${topicArn}`);
12248
12248
  }
12249
12249
  throw innerError;
12250
12250
  }
@@ -12974,6 +12974,88 @@ function mapDeliveryStatusLogging(attrs, stateCaseMap = /* @__PURE__ */ new Map(
12974
12974
  return result;
12975
12975
  }
12976
12976
 
12977
+ //#endregion
12978
+ //#region src/provisioning/attribute-map.ts
12979
+ /**
12980
+ * The ONE spelling of the attribute-map rule an SDK provider's `create()` /
12981
+ * `update()` / `import()` result follows (issue #3077, closing the `?? ''`
12982
+ * shape `docs/provider-development.md` forbids under "Never store an
12983
+ * empty-string placeholder"):
12984
+ *
12985
+ * an attribute cdkd could not read back is ABSENT from the map — never
12986
+ * recorded as the empty string, and never as a present-but-`undefined` key.
12987
+ *
12988
+ * The consumers of `ResourceState.attributes` all key off exactly that
12989
+ * distinction, and a sentinel puts every one of them on the wrong branch:
12990
+ *
12991
+ * - the deploy engine persists the map as-is, so `''` becomes the recorded
12992
+ * value of a field AWS never assigned;
12993
+ * - the intrinsic resolver serves a stored attribute whenever it is not
12994
+ * `undefined`, so `''` shadows `constructAttribute` forever — the
12995
+ * `AWS::EC2::Instance` IP / DNS / AZ arm re-describes the instance from
12996
+ * AWS only on a MISS, the `Arn` arms of the RDS family rebuild the ARN
12997
+ * only on a MISS;
12998
+ * - the Outputs export pass publishes whatever the resolver returned, so a
12999
+ * stored `''` is exported to every `Fn::ImportValue` consumer.
13000
+ *
13001
+ * It exists as a MODULE rather than a per-provider idiom because the rule was
13002
+ * prose and 96 attribute-position `?? ''` / `|| ''` / bare `''` sites across
13003
+ * 18 providers shipped anyway (measured 2026-09-14 with the TypeScript-compiler
13004
+ * walk that is now `tests/unit/provisioning/attribute-map.test.ts`). A helper
13005
+ * that DROPS the key is the one form a provider cannot spell wrong by habit.
13006
+ *
13007
+ * Two values are treated as "not read back":
13008
+ *
13009
+ * - `undefined`: the SDK's spelling of an unassigned optional member.
13010
+ * - `null`: no AWS SDK v3 read-back reports a scalar attribute as `null`, and
13011
+ * a stored `null` takes the resolver's "not `undefined`" hit branch exactly
13012
+ * like `''` does.
13013
+ *
13014
+ * Every other value is kept verbatim — INCLUDING an empty string AWS itself
13015
+ * reported (`false`, `0`, an empty array and an object likewise). The helper
13016
+ * stops cdkd MANUFACTURING `''` for a field it never read; a `''` that came
13017
+ * off the wire is a known value with a meaning the provider owns. The EC2
13018
+ * Instance provider is where that distinction is load-bearing: a `running`
13019
+ * instance with no public address is described with `PublicDnsName: ''` and
13020
+ * no `PublicIpAddress`, and CloudFormation answers `''` for both — a KNOWN
13021
+ * empty, recorded as such so a reference does not degrade to the instance id
13022
+ * on every resolution — while the same `''` on a `pending` instance means
13023
+ * "not yet", which that provider maps to `undefined` BEFORE calling this
13024
+ * helper (its `describedInstanceAttributes`). A caller that knows a `''`
13025
+ * means "unknown" is the one that must say so; this helper cannot tell.
13026
+ *
13027
+ * Deliberately NOT a general "compact this record" utility: it is scoped to
13028
+ * attribute maps. A property bag keeps its `undefined`-valued keys out by other
13029
+ * means (`.claude/rules/provider-property-fidelity.md`, "Remove the key rather
13030
+ * than setting it to `undefined`").
13031
+ *
13032
+ * A LEAF module (imports nothing) so every provider can take it without adding
13033
+ * an edge to the provider import ring.
13034
+ */
13035
+ /**
13036
+ * Build an attribute map from read-back values, omitting every key whose value
13037
+ * is `undefined` or `null`.
13038
+ */
13039
+ function definedAttributes(entries) {
13040
+ const out = {};
13041
+ for (const [key, value] of Object.entries(entries)) {
13042
+ if (value === void 0 || value === null) continue;
13043
+ out[key] = value;
13044
+ }
13045
+ return out;
13046
+ }
13047
+ /**
13048
+ * `String(value)` for a numeric read-back whose CloudFormation attribute is a
13049
+ * string (`Endpoint.Port`), or `undefined` when the field is unassigned — so
13050
+ * `definedAttributes` drops the key instead of recording the literal
13051
+ * `'undefined'`, which is what `String(described?.Port ?? '')` yields once its
13052
+ * `?? ''` is merely deleted.
13053
+ */
13054
+ function stringifyIfAssigned(value) {
13055
+ if (value === void 0 || value === null) return void 0;
13056
+ return String(value);
13057
+ }
13058
+
12977
13059
  //#endregion
12978
13060
  //#region src/provisioning/providers/sns-subscription-provider.ts
12979
13061
  /**
@@ -13046,17 +13128,18 @@ var SNSSubscriptionProvider = class {
13046
13128
  if (replayPolicy !== void 0) attributes["ReplayPolicy"] = typeof replayPolicy === "string" ? replayPolicy : JSON.stringify(replayPolicy);
13047
13129
  const subscriptionRoleArn = properties["SubscriptionRoleArn"];
13048
13130
  if (subscriptionRoleArn !== void 0) attributes["SubscriptionRoleArn"] = stringifyValue(subscriptionRoleArn);
13049
- const subscriptionArn = (await this.snsClient.send(new SubscribeCommand({
13131
+ const response = await this.snsClient.send(new SubscribeCommand({
13050
13132
  TopicArn: topicArn,
13051
13133
  Protocol: protocol,
13052
13134
  Endpoint: endpoint,
13053
13135
  ReturnSubscriptionArn: true,
13054
13136
  ...Object.keys(attributes).length > 0 && { Attributes: attributes }
13055
- }))).SubscriptionArn || `${topicArn}:${logicalId}`;
13137
+ }));
13138
+ const subscriptionArn = response.SubscriptionArn || `${topicArn}:${logicalId}`;
13056
13139
  this.logger.debug(`Successfully created SNS subscription ${logicalId}: ${subscriptionArn}`);
13057
13140
  return {
13058
13141
  physicalId: subscriptionArn,
13059
- attributes: {}
13142
+ attributes: definedAttributes({ Arn: response.SubscriptionArn?.startsWith("arn:") ? response.SubscriptionArn : void 0 })
13060
13143
  };
13061
13144
  } catch (error) {
13062
13145
  const cause = error instanceof Error ? error : void 0;
@@ -13077,7 +13160,7 @@ var SNSSubscriptionProvider = class {
13077
13160
  deleteResult = await this.delete(logicalId, physicalId, resourceType);
13078
13161
  } catch (error) {
13079
13162
  deleteThrew = true;
13080
- this.logger.warn(`Failed to delete old subscription ${physicalId} during update: ${String(error)}`);
13163
+ this.logger.warn(`Failed to delete old subscription ${physicalId} during update: ${safeStringify(error)}`);
13081
13164
  }
13082
13165
  const notDeletedReason = deleteThrew ? SNS_SUBSCRIPTION_DELETE_THREW_REASON : deleteResult?.outcome === "skipped" ? deleteResult.reason : void 0;
13083
13166
  if (notDeletedReason !== void 0) {
@@ -13657,7 +13740,7 @@ var LambdaFunctionProvider = class {
13657
13740
  try {
13658
13741
  await send();
13659
13742
  } catch (error) {
13660
- const message = error instanceof Error ? error.message : String(error);
13743
+ const message = describeAwsFailure(error).detail;
13661
13744
  this.logger.warn(`${ctx.apiName} failed for ${ctx.logicalId}: ${message} — deleting partially-created function to maintain atomicity`);
13662
13745
  let cleanupFailure;
13663
13746
  for (let attempt = 0; attempt < LAMBDA_CLEANUP_DELETE_MAX_ATTEMPTS; attempt++) try {
@@ -13665,7 +13748,7 @@ var LambdaFunctionProvider = class {
13665
13748
  cleanupFailure = void 0;
13666
13749
  break;
13667
13750
  } catch (deleteError) {
13668
- const deleteMessage = deleteError instanceof Error ? deleteError.message : String(deleteError);
13751
+ const deleteMessage = describeAwsFailure(deleteError).detail;
13669
13752
  cleanupFailure = deleteMessage;
13670
13753
  if (!/currently in the following state|ResourceConflict/i.test(deleteMessage)) break;
13671
13754
  if (attempt < 2) await new Promise((resolve) => setTimeout(resolve, this.cleanupDeleteRetryDelayMs * (attempt + 1)));
@@ -13858,7 +13941,7 @@ var LambdaFunctionProvider = class {
13858
13941
  assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, physicalId);
13859
13942
  return;
13860
13943
  }
13861
- this.logger.warn(`Pre-delete VPC detach failed for ${physicalId}: ${error instanceof Error ? error.message : String(error)} — continuing with delete`);
13944
+ this.logger.warn(`Pre-delete VPC detach failed for ${physicalId}: ${describeAwsFailure(error).detail} — continuing with delete`);
13862
13945
  }
13863
13946
  await this.waitForLambdaUpdateCompleted(physicalId);
13864
13947
  }
@@ -14060,7 +14143,7 @@ var LambdaFunctionProvider = class {
14060
14143
  status = (await this.lambdaClient.send(new GetFunctionCommand({ FunctionName: functionName }))).Configuration?.LastUpdateStatus;
14061
14144
  } catch (error) {
14062
14145
  if (error instanceof ResourceNotFoundException) return;
14063
- this.logger.debug(`GetFunction failed while waiting for ${functionName} update: ${error instanceof Error ? error.message : String(error)}`);
14146
+ this.logger.debug(`GetFunction failed while waiting for ${functionName} update: ${describeAwsFailure(error).detail}`);
14064
14147
  }
14065
14148
  if (status && status !== "InProgress") {
14066
14149
  this.logger.debug(`Lambda ${functionName} update completed (LastUpdateStatus=${status}) after ${Date.now() - start}ms`);
@@ -14084,7 +14167,7 @@ var LambdaFunctionProvider = class {
14084
14167
  try {
14085
14168
  enis = await this.listLambdaEnis(functionName);
14086
14169
  } catch (error) {
14087
- this.logger.warn(`DescribeNetworkInterfaces failed for ${functionName}: ${error instanceof Error ? error.message : String(error)} — downstream Subnet/SG deletion will fall back to its own ENI cleanup`);
14170
+ this.logger.warn(`DescribeNetworkInterfaces failed for ${functionName}: ${describeAwsFailure(error).detail} — downstream Subnet/SG deletion will fall back to its own ENI cleanup`);
14088
14171
  return;
14089
14172
  }
14090
14173
  if (enis.length === 0) {
@@ -14100,7 +14183,7 @@ var LambdaFunctionProvider = class {
14100
14183
  this.logger.debug(`Deleted Lambda ENI ${eniId} for ${functionName}`);
14101
14184
  return;
14102
14185
  } catch (error) {
14103
- const msg = error instanceof Error ? error.message : String(error);
14186
+ const msg = describeAwsFailure(error).detail;
14104
14187
  if (msg.includes("InvalidNetworkInterfaceID.NotFound") || msg.includes("does not exist")) return;
14105
14188
  const elapsed = Date.now() - start;
14106
14189
  if (elapsed >= this.eniDeleteRetryBudgetMs) {
@@ -14348,13 +14431,13 @@ var LambdaFunctionProvider = class {
14348
14431
  const rlResp = await this.lambdaClient.send(new GetFunctionRecursionConfigCommand({ FunctionName: physicalId }));
14349
14432
  if (rlResp.RecursiveLoop !== void 0) result["RecursiveLoop"] = rlResp.RecursiveLoop;
14350
14433
  } catch (rlErr) {
14351
- if (!(rlErr instanceof ResourceNotFoundException)) this.logger.debug(`GetFunctionRecursionConfig failed for ${physicalId}: ${rlErr instanceof Error ? rlErr.message : String(rlErr)}`);
14434
+ if (!(rlErr instanceof ResourceNotFoundException)) this.logger.debug(`GetFunctionRecursionConfig failed for ${physicalId}: ${describeAwsFailure(rlErr).detail}`);
14352
14435
  }
14353
14436
  try {
14354
14437
  const pcResp = await this.lambdaClient.send(new GetFunctionConcurrencyCommand({ FunctionName: physicalId }));
14355
14438
  if (pcResp.ReservedConcurrentExecutions !== void 0) result["ReservedConcurrentExecutions"] = pcResp.ReservedConcurrentExecutions;
14356
14439
  } catch (pcErr) {
14357
- if (!(pcErr instanceof ResourceNotFoundException)) this.logger.debug(`GetFunctionConcurrency failed for ${physicalId}: ${pcErr instanceof Error ? pcErr.message : String(pcErr)}`);
14440
+ if (!(pcErr instanceof ResourceNotFoundException)) this.logger.debug(`GetFunctionConcurrency failed for ${physicalId}: ${describeAwsFailure(pcErr).detail}`);
14358
14441
  }
14359
14442
  if (cfg.PackageType !== "Image") {
14360
14443
  try {
@@ -14365,13 +14448,13 @@ var LambdaFunctionProvider = class {
14365
14448
  result["RuntimeManagementConfig"] = rm;
14366
14449
  }
14367
14450
  } catch (rmErr) {
14368
- if (!(rmErr instanceof ResourceNotFoundException)) this.logger.warn(`GetRuntimeManagementConfig failed for ${physicalId} — RuntimeManagementConfig omitted from the drift snapshot (may surface as a false removal): ${rmErr instanceof Error ? rmErr.message : String(rmErr)}`);
14451
+ if (!(rmErr instanceof ResourceNotFoundException)) this.logger.warn(`GetRuntimeManagementConfig failed for ${physicalId} — RuntimeManagementConfig omitted from the drift snapshot (may surface as a false removal): ${describeAwsFailure(rmErr).detail}`);
14369
14452
  }
14370
14453
  try {
14371
14454
  const csResp = await this.lambdaClient.send(new GetFunctionCodeSigningConfigCommand({ FunctionName: physicalId }));
14372
14455
  if (csResp.CodeSigningConfigArn !== void 0) result["CodeSigningConfigArn"] = csResp.CodeSigningConfigArn;
14373
14456
  } catch (csErr) {
14374
- if (!(csErr instanceof ResourceNotFoundException)) this.logger.warn(`GetFunctionCodeSigningConfig failed for ${physicalId} — CodeSigningConfigArn omitted from the drift snapshot (may surface as a false removal): ${csErr instanceof Error ? csErr.message : String(csErr)}`);
14457
+ if (!(csErr instanceof ResourceNotFoundException)) this.logger.warn(`GetFunctionCodeSigningConfig failed for ${physicalId} — CodeSigningConfigArn omitted from the drift snapshot (may surface as a false removal): ${describeAwsFailure(csErr).detail}`);
14375
14458
  }
14376
14459
  }
14377
14460
  return result;
@@ -16784,7 +16867,7 @@ async function waitForIndexesSettled(opts) {
16784
16867
  try {
16785
16868
  if (!hasTransitionalIndex((await describeTable()).Table?.GlobalSecondaryIndexes ?? [])) return;
16786
16869
  } catch (err) {
16787
- const message = err instanceof Error ? err.message : String(err);
16870
+ const message = describeAwsFailure(err).detail;
16788
16871
  if (isThrottlingError(err)) {
16789
16872
  logger.debug(`DescribeTable throttled while waiting for indexes on ${tableName} (attempt ${attempt}/${maxAttempts}); still waiting: ${message}`);
16790
16873
  await new Promise((resolve) => setTimeout(resolve, INDEX_SETTLE_POLL_INTERVAL_MS));
@@ -17603,7 +17686,7 @@ async function compensateRemovedDeletionProtection(opts) {
17603
17686
  opts.logger.warn(`DynamoDB ${opts.typeLabel} ${opts.logicalId}: the delete failed after --remove-protection had turned DeletionProtectionEnabled off, so it was re-enabled on ${opts.physicalId}. The delete failure below is the outcome.`);
17604
17687
  return "restored";
17605
17688
  } catch (reEnableError) {
17606
- const detail = reEnableError instanceof Error ? reEnableError.message : String(reEnableError);
17689
+ const detail = describeAwsFailure(reEnableError).detail;
17607
17690
  if (isResourceNotFoundError(reEnableError)) {
17608
17691
  const regionArg = opts.region ? ` --region ${opts.region}` : "";
17609
17692
  opts.logger.warn(`DynamoDB ${opts.typeLabel} ${opts.logicalId}: could not re-enable DeletionProtectionEnabled on ${opts.physicalId} after the delete failed — DynamoDB answered ResourceNotFound. That most commonly means the table is gone or its status is not ACTIVE, and it can also mean the table is not in this region or account. If it still exists, its deletion protection is OFF. Check with: aws dynamodb describe-table --table-name ${opts.physicalId}${regionArg} and if it is there, restore it with: aws dynamodb update-table --table-name ${opts.physicalId}${regionArg} --deletion-protection-enabled. (${detail})`);
@@ -18455,7 +18538,7 @@ var DynamoDBTableProvider = class {
18455
18538
  await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
18456
18539
  debug(`Rolled back partially-created DynamoDB table ${tableName}`);
18457
18540
  } catch (cleanupError) {
18458
- warn(`Failed to roll back partially-created DynamoDB table ${tableName}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
18541
+ warn(`Failed to roll back partially-created DynamoDB table ${tableName}: ${describeAwsFailure(cleanupError).detail}`);
18459
18542
  }
18460
18543
  if (error instanceof ProvisioningError) throw error;
18461
18544
  const cause = error instanceof Error ? error : void 0;
@@ -18732,7 +18815,7 @@ var DynamoDBTableProvider = class {
18732
18815
  try {
18733
18816
  observedProtectionOn = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.DeletionProtectionEnabled === true;
18734
18817
  } catch (observeError) {
18735
- this.logger.debug(`Could not read DeletionProtectionEnabled on ${physicalId} before disabling it: ${observeError instanceof Error ? observeError.message : String(observeError)}`);
18818
+ this.logger.debug(`Could not read DeletionProtectionEnabled on ${physicalId} before disabling it: ${describeAwsFailure(observeError).detail}`);
18736
18819
  }
18737
18820
  await this.dynamoDBClient.send(new UpdateTableCommand({
18738
18821
  TableName: physicalId,
@@ -18743,10 +18826,10 @@ var DynamoDBTableProvider = class {
18743
18826
  try {
18744
18827
  await this.waitForTableActiveAfterUpdate(physicalId, 60, budget);
18745
18828
  } catch (waitErr) {
18746
- this.logger.debug(`Could not wait for table ${physicalId} ACTIVE after disabling protection: ${waitErr instanceof Error ? waitErr.message : String(waitErr)}`);
18829
+ this.logger.debug(`Could not wait for table ${physicalId} ACTIVE after disabling protection: ${describeAwsFailure(waitErr).detail}`);
18747
18830
  }
18748
18831
  } catch (flipError) {
18749
- if (!(flipError instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not disable DeletionProtectionEnabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
18832
+ if (!(flipError instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not disable DeletionProtectionEnabled on ${physicalId}: ${describeAwsFailure(flipError).detail}`);
18750
18833
  }
18751
18834
  try {
18752
18835
  const reArmPolls = () => {
@@ -18883,7 +18966,7 @@ var DynamoDBTableProvider = class {
18883
18966
  for (let attempt = 1;; attempt++) try {
18884
18967
  return await op();
18885
18968
  } catch (error) {
18886
- const msg = error instanceof Error ? error.message : String(error);
18969
+ const msg = describeAwsFailure(error).detail;
18887
18970
  const name = error instanceof Error ? error.name : "";
18888
18971
  if (!(/being enabled|being updated|please retry later|backups are being/i.test(msg) || name === "ResourceInUseException" || name === "LimitExceededException") || attempt >= maxAttempts) throw error;
18889
18972
  this.logger.debug(`Transient error on "${label}" (attempt ${attempt}/${maxAttempts}): ${msg} — retrying in ${delayMs}ms`);
@@ -19959,7 +20042,7 @@ var DynamoDBTableProvider = class {
19959
20042
  result["PointInTimeRecoverySpecification"] = pitr;
19960
20043
  }
19961
20044
  } catch (err) {
19962
- this.logger.debug(`Could not read PointInTimeRecovery for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
20045
+ this.logger.debug(`Could not read PointInTimeRecovery for ${physicalId}: ${describeAwsFailure(err).detail}`);
19963
20046
  }
19964
20047
  try {
19965
20048
  const ttlDesc = (await this.dynamoDBClient.send(new DescribeTimeToLiveCommand({ TableName: physicalId }))).TimeToLiveDescription;
@@ -19968,7 +20051,7 @@ var DynamoDBTableProvider = class {
19968
20051
  Enabled: true
19969
20052
  };
19970
20053
  } catch (err) {
19971
- this.logger.debug(`Could not read TimeToLive for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
20054
+ this.logger.debug(`Could not read TimeToLive for ${physicalId}: ${describeAwsFailure(err).detail}`);
19972
20055
  }
19973
20056
  if (table.TableArn) try {
19974
20057
  const rpResp = await this.dynamoDBClient.send(new GetResourcePolicyCommand({ ResourceArn: table.TableArn }));
@@ -19980,7 +20063,7 @@ var DynamoDBTableProvider = class {
19980
20063
  result["ResourcePolicy"] = { PolicyDocument: doc };
19981
20064
  }
19982
20065
  } catch (err) {
19983
- if (!(err instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not read ResourcePolicy for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
20066
+ if (!(err instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not read ResourcePolicy for ${physicalId}: ${describeAwsFailure(err).detail}`);
19984
20067
  }
19985
20068
  try {
19986
20069
  const active = ((await this.dynamoDBClient.send(new DescribeKinesisStreamingDestinationCommand({ TableName: physicalId }))).KinesisDataStreamDestinations ?? []).find((d) => d.DestinationStatus === "ACTIVE" || d.DestinationStatus === "ENABLING");
@@ -19990,7 +20073,7 @@ var DynamoDBTableProvider = class {
19990
20073
  result["KinesisStreamSpecification"] = kspec;
19991
20074
  }
19992
20075
  } catch (err) {
19993
- this.logger.debug(`Could not read KinesisStreamingDestination for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
20076
+ this.logger.debug(`Could not read KinesisStreamingDestination for ${physicalId}: ${describeAwsFailure(err).detail}`);
19994
20077
  }
19995
20078
  try {
19996
20079
  const ciResp = await this.dynamoDBClient.send(new DescribeContributorInsightsCommand({ TableName: physicalId }));
@@ -20001,7 +20084,7 @@ var DynamoDBTableProvider = class {
20001
20084
  result["ContributorInsightsSpecification"] = cspec;
20002
20085
  }
20003
20086
  } catch (err) {
20004
- this.logger.debug(`Could not read ContributorInsights for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
20087
+ this.logger.debug(`Could not read ContributorInsights for ${physicalId}: ${describeAwsFailure(err).detail}`);
20005
20088
  }
20006
20089
  return result;
20007
20090
  } catch (err) {
@@ -20500,7 +20583,7 @@ var DynamoDBGlobalTableProvider = class {
20500
20583
  if (billingMode === "PROVISIONED") try {
20501
20584
  await this.reconcileAutoScalingTargets(tableName, [], collectAutoScalingTargets(properties, currentRegion), currentRegion, void 0, maskSecrets);
20502
20585
  } catch (autoScalingErr) {
20503
- warn(`Auto-scaling registration failed for ${tableName}: ${autoScalingErr instanceof Error ? autoScalingErr.message : String(autoScalingErr)}. The table was created successfully; re-run the deploy to register the scaling targets.`);
20586
+ warn(`Auto-scaling registration failed for ${tableName}: ${describeAwsFailure(autoScalingErr).detail}. The table was created successfully; re-run the deploy to register the scaling targets.`);
20504
20587
  }
20505
20588
  this.logger.debug(`Successfully created DynamoDB GlobalTable ${logicalId}: ${tableName}`);
20506
20589
  return {
@@ -20527,12 +20610,14 @@ var DynamoDBGlobalTableProvider = class {
20527
20610
  }));
20528
20611
  await this.waitForReplicaGone(tableName, region, logicalId);
20529
20612
  } catch (replicaCleanupErr) {
20530
- warn(`Partial-create cleanup: failed to drop replica ${region} on ${tableName}: ${replicaCleanupErr instanceof Error ? replicaCleanupErr.message : String(replicaCleanupErr)}. Run: aws dynamodb update-table --table-name ${tableName} --replica-updates 'Delete={RegionName=${region}}' --region ${currentRegion}`);
20613
+ const msg = describeAwsFailure(replicaCleanupErr).detail;
20614
+ warn(`Partial-create cleanup: failed to drop replica ${region} on ${tableName}: ${msg}. Run: aws dynamodb update-table --table-name ${tableName} --replica-updates 'Delete={RegionName=${region}}' --region ${currentRegion}`);
20531
20615
  }
20532
20616
  }
20533
20617
  await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
20534
20618
  } catch (cleanupErr) {
20535
- warn(`Partial-create cleanup failed for ${tableName}: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}. Run: aws dynamodb delete-table --table-name ${tableName} to remove the orphaned AWS-side table.`);
20619
+ const cleanupMsg = describeAwsFailure(cleanupErr).detail;
20620
+ warn(`Partial-create cleanup failed for ${tableName}: ${cleanupMsg}. Run: aws dynamodb delete-table --table-name ${tableName} to remove the orphaned AWS-side table.`);
20536
20621
  }
20537
20622
  const cause = wiringError instanceof Error ? wiringError : void 0;
20538
20623
  throw new ProvisioningError(`Failed to create DynamoDB GlobalTable ${logicalId}: ${wiringError instanceof Error ? wiringError.message : String(wiringError)}`, resourceType, logicalId, tableName, cause);
@@ -21149,7 +21234,7 @@ var DynamoDBGlobalTableProvider = class {
21149
21234
  const regionalClient = this.getRegionalClient(region);
21150
21235
  await this.applyTagDiffOnClient(regionalClient, replicaArn, oldTags, newTags);
21151
21236
  } catch (tagErr) {
21152
- warn(`Could not apply Tags diff to cross-region replica ${region} of ${physicalIdForLogs}: ${tagErr instanceof Error ? tagErr.message : String(tagErr)}. The replica's Tags state will surface as drift until the next successful deploy.`);
21237
+ warn(`Could not apply Tags diff to cross-region replica ${region} of ${physicalIdForLogs}: ${describeAwsFailure(tagErr).detail}. The replica's Tags state will surface as drift until the next successful deploy.`);
21153
21238
  }
21154
21239
  }
21155
21240
  /**
@@ -21261,7 +21346,7 @@ var DynamoDBGlobalTableProvider = class {
21261
21346
  });
21262
21347
  } catch (err) {
21263
21348
  if (isInterruptedWaitError(err)) throw err;
21264
- warn(`Could not register auto-scaling target on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling register-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension} --min-capacity ${minCapacity} --max-capacity ${maxCapacity}`);
21349
+ warn(`Could not register auto-scaling target on ${tableName} (${dimension}): ${describeAwsFailure(err).detail}. Run: aws application-autoscaling register-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension} --min-capacity ${minCapacity} --max-capacity ${maxCapacity}`);
21265
21350
  return;
21266
21351
  }
21267
21352
  const tttCfg = newSettings["TargetTrackingScalingPolicyConfiguration"] ?? {};
@@ -21303,7 +21388,7 @@ var DynamoDBGlobalTableProvider = class {
21303
21388
  this.logger.debug(`Upserted auto-scaling policy ${policyName} on ${tableName} (${dimension})`);
21304
21389
  } catch (err) {
21305
21390
  if (isInterruptedWaitError(err)) throw err;
21306
- warn(`Could not put auto-scaling policy on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling put-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension} --policy-type TargetTrackingScaling`);
21391
+ warn(`Could not put auto-scaling policy on ${tableName} (${dimension}): ${describeAwsFailure(err).detail}. Run: aws application-autoscaling put-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension} --policy-type TargetTrackingScaling`);
21307
21392
  }
21308
21393
  return;
21309
21394
  }
@@ -21328,7 +21413,7 @@ var DynamoDBGlobalTableProvider = class {
21328
21413
  });
21329
21414
  } catch (err) {
21330
21415
  if (isInterruptedWaitError(err)) throw err;
21331
- if (!isObjectNotFound(err)) warn(`Could not delete auto-scaling policy on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling delete-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
21416
+ if (!isObjectNotFound(err)) warn(`Could not delete auto-scaling policy on ${tableName} (${dimension}): ${describeAwsFailure(err).detail}. Run: aws application-autoscaling delete-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
21332
21417
  }
21333
21418
  try {
21334
21419
  await withRetry(() => asClient.send(new DeregisterScalableTargetCommand({
@@ -21345,7 +21430,7 @@ var DynamoDBGlobalTableProvider = class {
21345
21430
  this.logger.debug(`Deregistered auto-scaling target ${resourceId} (${dimension})`);
21346
21431
  } catch (err) {
21347
21432
  if (isInterruptedWaitError(err)) throw err;
21348
- if (!isObjectNotFound(err)) warn(`Could not deregister auto-scaling target on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling deregister-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
21433
+ if (!isObjectNotFound(err)) warn(`Could not deregister auto-scaling target on ${tableName} (${dimension}): ${describeAwsFailure(err).detail}. Run: aws application-autoscaling deregister-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
21349
21434
  }
21350
21435
  } finally {
21351
21436
  watch.dispose();
@@ -21426,7 +21511,7 @@ var DynamoDBGlobalTableProvider = class {
21426
21511
  policyToken = res.NextToken;
21427
21512
  } while (policyToken);
21428
21513
  } catch (err) {
21429
- this.logger.debug(`Could not probe existing auto-scaling targets on ${tableName} in ${region}: ${err instanceof Error ? err.message : String(err)} — re-asserting every target instead.`);
21514
+ this.logger.debug(`Could not probe existing auto-scaling targets on ${tableName} in ${region}: ${describeAwsFailure(err).detail} — re-asserting every target instead.`);
21430
21515
  return null;
21431
21516
  }
21432
21517
  }
@@ -21527,7 +21612,7 @@ var DynamoDBGlobalTableProvider = class {
21527
21612
  try {
21528
21613
  observedProtectionOn = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.DeletionProtectionEnabled === true;
21529
21614
  } catch (observeError) {
21530
- this.logger.debug(`Could not read DeletionProtectionEnabled on ${physicalId} before disabling it: ${observeError instanceof Error ? observeError.message : String(observeError)}`);
21615
+ this.logger.debug(`Could not read DeletionProtectionEnabled on ${physicalId} before disabling it: ${describeAwsFailure(observeError).detail}`);
21531
21616
  }
21532
21617
  await this.dynamoDBClient.send(new UpdateTableCommand({
21533
21618
  TableName: physicalId,
@@ -21538,10 +21623,10 @@ var DynamoDBGlobalTableProvider = class {
21538
21623
  try {
21539
21624
  await this.waitForTableActiveAfterUpdate(physicalId, logicalId, 600, budget);
21540
21625
  } catch (waitErr) {
21541
- this.logger.debug(`Could not wait for table ${physicalId} ACTIVE after protection flip: ${waitErr instanceof Error ? waitErr.message : String(waitErr)}`);
21626
+ this.logger.debug(`Could not wait for table ${physicalId} ACTIVE after protection flip: ${describeAwsFailure(waitErr).detail}`);
21542
21627
  }
21543
21628
  } catch (flipError) {
21544
- if (!(flipError instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not disable DeletionProtectionEnabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
21629
+ if (!(flipError instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not disable DeletionProtectionEnabled on ${physicalId}: ${describeAwsFailure(flipError).detail}`);
21545
21630
  }
21546
21631
  let currentRegion;
21547
21632
  try {
@@ -21583,7 +21668,7 @@ var DynamoDBGlobalTableProvider = class {
21583
21668
  if (isInterruptedWaitError(describeErr)) throw describeErr;
21584
21669
  if (!(describeErr instanceof ResourceNotFoundException$1)) {
21585
21670
  const cause = describeErr instanceof Error ? describeErr : void 0;
21586
- throw new ProvisioningError(`Failed to describe DynamoDB GlobalTable ${logicalId} before delete: ${describeErr instanceof Error ? describeErr.message : String(describeErr)}`, resourceType, logicalId, physicalId, cause);
21671
+ throw new ProvisioningError(`Failed to describe DynamoDB GlobalTable ${logicalId} before delete: ${describeAwsFailure(describeErr).detail}`, resourceType, logicalId, physicalId, cause);
21587
21672
  }
21588
21673
  }
21589
21674
  try {
@@ -21742,7 +21827,7 @@ var DynamoDBGlobalTableProvider = class {
21742
21827
  this.logger.debug(`Cross-region replica ${regionLabel} returned RNF on ListTagsOfResource; omitting Tags`);
21743
21828
  entry["Tags"] = [];
21744
21829
  } else {
21745
- this.logger.warn(`Could not fetch tags for DynamoDB GlobalTable ${tableNameForSubs} in ${regionLabel}: ${tagErr instanceof Error ? tagErr.message : String(tagErr)}`);
21830
+ this.logger.warn(`Could not fetch tags for DynamoDB GlobalTable ${tableNameForSubs} in ${regionLabel}: ${describeAwsFailure(tagErr).detail}`);
21746
21831
  entry["Tags"] = [];
21747
21832
  }
21748
21833
  }
@@ -21809,7 +21894,7 @@ var DynamoDBGlobalTableProvider = class {
21809
21894
  };
21810
21895
  else if (ttlStatus === "DISABLED") {}
21811
21896
  } catch (ttlErr) {
21812
- this.logger.debug(`Could not read TimeToLive for ${tableNameForSubs}: ${ttlErr instanceof Error ? ttlErr.message : String(ttlErr)}`);
21897
+ this.logger.debug(`Could not read TimeToLive for ${tableNameForSubs}: ${describeAwsFailure(ttlErr).detail}`);
21813
21898
  }
21814
21899
  return result;
21815
21900
  } catch (err) {
@@ -21843,13 +21928,13 @@ var DynamoDBGlobalTableProvider = class {
21843
21928
  const ci = await client.send(new DescribeContributorInsightsCommand({ TableName: tableName }));
21844
21929
  if (ci.ContributorInsightsStatus) out["ContributorInsightsSpecification"] = { Enabled: ci.ContributorInsightsStatus === "ENABLED" };
21845
21930
  } catch (err) {
21846
- this.logger.debug(`Could not read ContributorInsights for ${tableName} in ${regionLabel}: ${err instanceof Error ? err.message : String(err)}`);
21931
+ this.logger.debug(`Could not read ContributorInsights for ${tableName} in ${regionLabel}: ${describeAwsFailure(err).detail}`);
21847
21932
  }
21848
21933
  try {
21849
21934
  const pitrStatus = (await client.send(new DescribeContinuousBackupsCommand({ TableName: tableName }))).ContinuousBackupsDescription?.PointInTimeRecoveryDescription?.PointInTimeRecoveryStatus;
21850
21935
  if (pitrStatus) out["PointInTimeRecoverySpecification"] = { PointInTimeRecoveryEnabled: pitrStatus === "ENABLED" };
21851
21936
  } catch (err) {
21852
- this.logger.debug(`Could not read PointInTimeRecovery for ${tableName} in ${regionLabel}: ${err instanceof Error ? err.message : String(err)}`);
21937
+ this.logger.debug(`Could not read PointInTimeRecovery for ${tableName} in ${regionLabel}: ${describeAwsFailure(err).detail}`);
21853
21938
  }
21854
21939
  try {
21855
21940
  const active = ((await client.send(new DescribeKinesisStreamingDestinationCommand({ TableName: tableName }))).KinesisDataStreamDestinations ?? []).find((d) => d.DestinationStatus === "ACTIVE" || d.DestinationStatus === "ENABLING");
@@ -21859,7 +21944,7 @@ var DynamoDBGlobalTableProvider = class {
21859
21944
  out["KinesisStreamSpecification"] = ksOut;
21860
21945
  }
21861
21946
  } catch (err) {
21862
- this.logger.debug(`Could not read KinesisStreamingDestination for ${tableName} in ${regionLabel}: ${err instanceof Error ? err.message : String(err)}`);
21947
+ this.logger.debug(`Could not read KinesisStreamingDestination for ${tableName} in ${regionLabel}: ${describeAwsFailure(err).detail}`);
21863
21948
  }
21864
21949
  return out;
21865
21950
  }
@@ -21955,7 +22040,7 @@ var DynamoDBGlobalTableProvider = class {
21955
22040
  TargetTrackingScalingPolicyConfiguration: tttConfig
21956
22041
  };
21957
22042
  } catch (err) {
21958
- this.logger.debug(`Could not read application-autoscaling settings for ${resourceId} (${scalableDimension}): ${err instanceof Error ? err.message : String(err)}`);
22043
+ this.logger.debug(`Could not read application-autoscaling settings for ${resourceId} (${scalableDimension}): ${describeAwsFailure(err).detail}`);
21959
22044
  return null;
21960
22045
  }
21961
22046
  }
@@ -23979,7 +24064,7 @@ var LogsLogGroupProvider = class {
23979
24064
  identifier: logGroupName
23980
24065
  });
23981
24066
  const manualStep = deleteCommand ? `Manual deletion may be required before the next deploy: ${deleteCommand}` : "Manual deletion may be required before the next deploy, via the console: the log group name cannot be reproduced safely on a command line.";
23982
- this.logger.warn(`Failed to clean up partially-created log group ${logicalId} (${logGroupName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. ${manualStep}`);
24067
+ this.logger.warn(`Failed to clean up partially-created log group ${logicalId} (${logGroupName}): ${describeAwsFailure(cleanupError).detail}. ${manualStep}`);
23983
24068
  }
23984
24069
  throw innerError;
23985
24070
  }
@@ -24163,7 +24248,7 @@ var LogsLogGroupProvider = class {
24163
24248
  }));
24164
24249
  this.logger.debug(`Disabled DeletionProtectionEnabled on log group ${logicalId} before delete`);
24165
24250
  } catch (flipError) {
24166
- this.logger.debug(`Could not disable DeletionProtectionEnabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
24251
+ this.logger.debug(`Could not disable DeletionProtectionEnabled on ${physicalId}: ${describeAwsFailure(flipError).detail}`);
24167
24252
  }
24168
24253
  try {
24169
24254
  await this.logsClient.send(new DeleteLogGroupCommand({ logGroupName: physicalId }));
@@ -24456,7 +24541,7 @@ var CloudWatchAlarmProvider = class {
24456
24541
  const compositeArn = response.CompositeAlarms?.[0]?.AlarmArn;
24457
24542
  if (compositeArn) return compositeArn;
24458
24543
  } catch (error) {
24459
- this.logger.debug(`Failed to describe alarm ${alarmName}, constructing ARN from config: ${error instanceof Error ? error.message : String(error)}`);
24544
+ this.logger.debug(`Failed to describe alarm ${alarmName}, constructing ARN from config: ${describeAwsFailure(error).detail}`);
24460
24545
  }
24461
24546
  try {
24462
24547
  const region = await this.cloudWatchClient.config.region() || process.env["AWS_REGION"] || "us-east-1";
@@ -24630,7 +24715,7 @@ var CloudWatchAlarmProvider = class {
24630
24715
  const tagsResp = await this.cloudWatchClient.send(new ListTagsForResourceCommand$4({ ResourceARN: alarm.AlarmArn }));
24631
24716
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
24632
24717
  } catch (err) {
24633
- this.logger.debug(`CloudWatch ListTagsForResource(${alarm.AlarmArn}) failed: ${err instanceof Error ? err.message : String(err)}`);
24718
+ this.logger.debug(`CloudWatch ListTagsForResource(${alarm.AlarmArn}) failed: ${describeAwsFailure(err).detail}`);
24634
24719
  }
24635
24720
  return result;
24636
24721
  }
@@ -25662,7 +25747,7 @@ var SSMParameterProvider = class {
25662
25747
  try {
25663
25748
  return await this.buildParameterArnUnguarded(name, mask);
25664
25749
  } catch (error) {
25665
- this.logger.warn(mask(`Could not build the Arn attribute for SSM parameter ${name}: ${error instanceof Error ? error.message : String(error)}. The parameter itself is unaffected; the Arn is NOT recorded, so an Fn::GetAtt on it will fail until a later deploy records it.`));
25750
+ this.logger.warn(mask(`Could not build the Arn attribute for SSM parameter ${name}: ${describeAwsFailure(error).detail}. The parameter itself is unaffected; the Arn is NOT recorded, so an Fn::GetAtt on it will fail until a later deploy records it.`));
25666
25751
  return;
25667
25752
  }
25668
25753
  }
@@ -25739,7 +25824,7 @@ var SSMParameterProvider = class {
25739
25824
  maskSecrets: mask
25740
25825
  });
25741
25826
  const manualStep = deleteCommand ? `Manual deletion may be required before the next deploy: ${deleteCommand}` : "Manual deletion may be required before the next deploy, via the console: the parameter name cannot be reproduced safely on a command line, and a command naming the sanitized form would delete a DIFFERENT parameter.";
25742
- warn(`Failed to clean up partially-created SSM parameter ${logicalId} (${name}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. ${manualStep}`);
25827
+ warn(`Failed to clean up partially-created SSM parameter ${logicalId} (${name}): ${describeAwsFailure(cleanupError).detail}. ${manualStep}`);
25743
25828
  }
25744
25829
  throw innerError;
25745
25830
  }
@@ -26185,7 +26270,7 @@ var EventBridgeRuleProvider = class {
26185
26270
  }));
26186
26271
  this.logger.debug(`Cleaned up partially-created EventBridge rule ${logicalId} (${ruleName}) after wiring failure`);
26187
26272
  } catch (cleanupError) {
26188
- this.logger.warn(`Failed to clean up partially-created EventBridge rule ${logicalId} (${ruleName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws events list-targets-by-rule --rule ${ruleName}${eventBusName ? ` --event-bus-name ${eventBusName}` : ""} | jq -r '.Targets[].Id' | xargs aws events remove-targets --rule ${ruleName}${eventBusName ? ` --event-bus-name ${eventBusName}` : ""} --ids; aws events delete-rule --name ${ruleName}${eventBusName ? ` --event-bus-name ${eventBusName}` : ""}`);
26273
+ this.logger.warn(`Failed to clean up partially-created EventBridge rule ${logicalId} (${ruleName}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws events list-targets-by-rule --rule ${ruleName}${eventBusName ? ` --event-bus-name ${eventBusName}` : ""} | jq -r '.Targets[].Id' | xargs aws events remove-targets --rule ${ruleName}${eventBusName ? ` --event-bus-name ${eventBusName}` : ""} --ids; aws events delete-rule --name ${ruleName}${eventBusName ? ` --event-bus-name ${eventBusName}` : ""}`);
26189
26274
  }
26190
26275
  throw innerError;
26191
26276
  }
@@ -26466,88 +26551,6 @@ var EventBridgeRuleProvider = class {
26466
26551
  }
26467
26552
  };
26468
26553
 
26469
- //#endregion
26470
- //#region src/provisioning/attribute-map.ts
26471
- /**
26472
- * The ONE spelling of the attribute-map rule an SDK provider's `create()` /
26473
- * `update()` / `import()` result follows (issue #3077, closing the `?? ''`
26474
- * shape `docs/provider-development.md` forbids under "Never store an
26475
- * empty-string placeholder"):
26476
- *
26477
- * an attribute cdkd could not read back is ABSENT from the map — never
26478
- * recorded as the empty string, and never as a present-but-`undefined` key.
26479
- *
26480
- * The consumers of `ResourceState.attributes` all key off exactly that
26481
- * distinction, and a sentinel puts every one of them on the wrong branch:
26482
- *
26483
- * - the deploy engine persists the map as-is, so `''` becomes the recorded
26484
- * value of a field AWS never assigned;
26485
- * - the intrinsic resolver serves a stored attribute whenever it is not
26486
- * `undefined`, so `''` shadows `constructAttribute` forever — the
26487
- * `AWS::EC2::Instance` IP / DNS / AZ arm re-describes the instance from
26488
- * AWS only on a MISS, the `Arn` arms of the RDS family rebuild the ARN
26489
- * only on a MISS;
26490
- * - the Outputs export pass publishes whatever the resolver returned, so a
26491
- * stored `''` is exported to every `Fn::ImportValue` consumer.
26492
- *
26493
- * It exists as a MODULE rather than a per-provider idiom because the rule was
26494
- * prose and 96 attribute-position `?? ''` / `|| ''` / bare `''` sites across
26495
- * 18 providers shipped anyway (measured 2026-09-14 with the TypeScript-compiler
26496
- * walk that is now `tests/unit/provisioning/attribute-map.test.ts`). A helper
26497
- * that DROPS the key is the one form a provider cannot spell wrong by habit.
26498
- *
26499
- * Two values are treated as "not read back":
26500
- *
26501
- * - `undefined`: the SDK's spelling of an unassigned optional member.
26502
- * - `null`: no AWS SDK v3 read-back reports a scalar attribute as `null`, and
26503
- * a stored `null` takes the resolver's "not `undefined`" hit branch exactly
26504
- * like `''` does.
26505
- *
26506
- * Every other value is kept verbatim — INCLUDING an empty string AWS itself
26507
- * reported (`false`, `0`, an empty array and an object likewise). The helper
26508
- * stops cdkd MANUFACTURING `''` for a field it never read; a `''` that came
26509
- * off the wire is a known value with a meaning the provider owns. The EC2
26510
- * Instance provider is where that distinction is load-bearing: a `running`
26511
- * instance with no public address is described with `PublicDnsName: ''` and
26512
- * no `PublicIpAddress`, and CloudFormation answers `''` for both — a KNOWN
26513
- * empty, recorded as such so a reference does not degrade to the instance id
26514
- * on every resolution — while the same `''` on a `pending` instance means
26515
- * "not yet", which that provider maps to `undefined` BEFORE calling this
26516
- * helper (its `describedInstanceAttributes`). A caller that knows a `''`
26517
- * means "unknown" is the one that must say so; this helper cannot tell.
26518
- *
26519
- * Deliberately NOT a general "compact this record" utility: it is scoped to
26520
- * attribute maps. A property bag keeps its `undefined`-valued keys out by other
26521
- * means (`.claude/rules/provider-property-fidelity.md`, "Remove the key rather
26522
- * than setting it to `undefined`").
26523
- *
26524
- * A LEAF module (imports nothing) so every provider can take it without adding
26525
- * an edge to the provider import ring.
26526
- */
26527
- /**
26528
- * Build an attribute map from read-back values, omitting every key whose value
26529
- * is `undefined` or `null`.
26530
- */
26531
- function definedAttributes(entries) {
26532
- const out = {};
26533
- for (const [key, value] of Object.entries(entries)) {
26534
- if (value === void 0 || value === null) continue;
26535
- out[key] = value;
26536
- }
26537
- return out;
26538
- }
26539
- /**
26540
- * `String(value)` for a numeric read-back whose CloudFormation attribute is a
26541
- * string (`Endpoint.Port`), or `undefined` when the field is unassigned — so
26542
- * `definedAttributes` drops the key instead of recording the literal
26543
- * `'undefined'`, which is what `String(described?.Port ?? '')` yields once its
26544
- * `?? ''` is merely deleted.
26545
- */
26546
- function stringifyIfAssigned(value) {
26547
- if (value === void 0 || value === null) return void 0;
26548
- return String(value);
26549
- }
26550
-
26551
26554
  //#endregion
26552
26555
  //#region src/provisioning/providers/eventbridge-bus-provider.ts
26553
26556
  /**
@@ -26701,7 +26704,7 @@ var EventBridgeBusProvider = class {
26701
26704
  this.logger.debug(`EventBus ${physicalId} does not exist, skipping`);
26702
26705
  return;
26703
26706
  }
26704
- const msg = error instanceof Error ? error.message : String(error);
26707
+ const msg = describeAwsFailure(error).detail;
26705
26708
  if (msg.includes("does not exist")) {
26706
26709
  const clientRegion = await this.eventBridgeClient.config.region();
26707
26710
  assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, physicalId);
@@ -26747,7 +26750,7 @@ var EventBridgeBusProvider = class {
26747
26750
  }
26748
26751
  } catch (error) {
26749
26752
  if (error instanceof ResourceNotFoundException$2) return;
26750
- this.logger.debug(`Failed to list rules on bus ${busName}: ${error instanceof Error ? error.message : String(error)}`);
26753
+ this.logger.debug(`Failed to list rules on bus ${busName}: ${describeAwsFailure(error).detail}`);
26751
26754
  }
26752
26755
  }
26753
26756
  /**
@@ -27558,7 +27561,7 @@ var EC2Provider = class {
27558
27561
  await this.ec2Client.send(new DeleteVpcCommand({ VpcId: vpcId }));
27559
27562
  this.logger.debug(`Cleaned up partially-created VPC ${logicalId} (${vpcId}) after wiring failure`);
27560
27563
  } catch (cleanupError) {
27561
- this.logger.warn(`Failed to clean up partially-created VPC ${logicalId} (${vpcId}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws ec2 delete-vpc --vpc-id ${vpcId}`);
27564
+ this.logger.warn(`Failed to clean up partially-created VPC ${logicalId} (${vpcId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws ec2 delete-vpc --vpc-id ${vpcId}`);
27562
27565
  }
27563
27566
  throw innerError;
27564
27567
  }
@@ -27624,7 +27627,7 @@ var EC2Provider = class {
27624
27627
  this.logger.debug(`VPC ${physicalId} does not exist, skipping deletion`);
27625
27628
  return;
27626
27629
  }
27627
- const msg = error instanceof Error ? error.message : String(error);
27630
+ const msg = describeAwsFailure(error).detail;
27628
27631
  if ((msg.includes("DependencyViolation") || msg.includes("has dependencies")) && attempt < maxAttempts) {
27629
27632
  this.logger.debug(`VPC ${physicalId} has dependencies (attempt ${attempt}/${maxAttempts}), retrying in ${attempt * 5}s...`);
27630
27633
  await new Promise((resolve) => setTimeout(resolve, attempt * 5e3));
@@ -27706,7 +27709,7 @@ var EC2Provider = class {
27706
27709
  await this.ec2Client.send(new DeleteSubnetCommand({ SubnetId: subnetId }));
27707
27710
  this.logger.debug(`Cleaned up partially-created Subnet ${logicalId} (${subnetId}) after wiring failure`);
27708
27711
  } catch (cleanupError) {
27709
- this.logger.warn(`Failed to clean up partially-created Subnet ${logicalId} (${subnetId}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws ec2 delete-subnet --subnet-id ${subnetId}`);
27712
+ this.logger.warn(`Failed to clean up partially-created Subnet ${logicalId} (${subnetId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws ec2 delete-subnet --subnet-id ${subnetId}`);
27710
27713
  }
27711
27714
  throw innerError;
27712
27715
  }
@@ -27777,7 +27780,7 @@ var EC2Provider = class {
27777
27780
  try {
27778
27781
  if ((await this.ec2Client.send(new DescribeSubnetsCommand({ SubnetIds: [subnetId] }))).Subnets?.[0]?.MapPublicIpOnLaunch === expected) return;
27779
27782
  } catch (error) {
27780
- this.logger.debug(`MapPublicIpOnLaunch read-back for ${subnetId} failed (attempt ${attempt}/${maxAttempts}): ${error instanceof Error ? error.message : String(error)}`);
27783
+ this.logger.debug(`MapPublicIpOnLaunch read-back for ${subnetId} failed (attempt ${attempt}/${maxAttempts}): ${describeAwsFailure(error).detail}`);
27781
27784
  return;
27782
27785
  }
27783
27786
  if (attempt < maxAttempts) await this.sleep(100 * 2 ** (attempt - 1));
@@ -27798,7 +27801,7 @@ var EC2Provider = class {
27798
27801
  this.logger.debug(`Subnet ${physicalId} does not exist, skipping deletion`);
27799
27802
  return;
27800
27803
  }
27801
- const msg = error instanceof Error ? error.message : String(error);
27804
+ const msg = describeAwsFailure(error).detail;
27802
27805
  if ((msg.includes("has dependencies") || msg.includes("DependencyViolation")) && attempt < maxAttempts) {
27803
27806
  await this.cleanupSubnetLambdaEnis(physicalId);
27804
27807
  this.logger.debug(`Subnet ${physicalId} has dependencies (attempt ${attempt}/${maxAttempts}), retrying in ${attempt * 5}s...`);
@@ -27831,7 +27834,7 @@ var EC2Provider = class {
27831
27834
  status: ni.Status ?? "unknown"
27832
27835
  }));
27833
27836
  } catch (err) {
27834
- this.logger.debug(`cleanupSubnetLambdaEnis: DescribeNetworkInterfaces failed for ${subnetId}: ${err instanceof Error ? err.message : String(err)}`);
27837
+ this.logger.debug(`cleanupSubnetLambdaEnis: DescribeNetworkInterfaces failed for ${subnetId}: ${describeAwsFailure(err).detail}`);
27835
27838
  return;
27836
27839
  }
27837
27840
  if (enis.length === 0) return;
@@ -27840,7 +27843,7 @@ var EC2Provider = class {
27840
27843
  await this.ec2Client.send(new DeleteNetworkInterfaceCommand({ NetworkInterfaceId: eni.id }));
27841
27844
  this.logger.debug(`cleanupSubnetLambdaEnis: deleted Lambda ENI ${eni.id} in subnet ${subnetId}`);
27842
27845
  } catch (err) {
27843
- this.logger.debug(`cleanupSubnetLambdaEnis: ENI ${eni.id} (status=${eni.status}) not yet deletable: ${err instanceof Error ? err.message : String(err)}`);
27846
+ this.logger.debug(`cleanupSubnetLambdaEnis: ENI ${eni.id} (status=${eni.status}) not yet deletable: ${describeAwsFailure(err).detail}`);
27844
27847
  }
27845
27848
  }));
27846
27849
  }
@@ -28148,7 +28151,7 @@ var EC2Provider = class {
28148
28151
  maxDelay: 10
28149
28152
  }, { NatGatewayIds: [physicalId] });
28150
28153
  } catch (error) {
28151
- this.logger.warn(`Wait for NatGateway ${physicalId} deletion did not complete cleanly: ${error instanceof Error ? error.message : String(error)} — proceeding with downstream delete steps`);
28154
+ this.logger.warn(`Wait for NatGateway ${physicalId} deletion did not complete cleanly: ${describeAwsFailure(error).detail} — proceeding with downstream delete steps`);
28152
28155
  }
28153
28156
  this.logger.debug(`Successfully deleted NatGateway ${logicalId}`);
28154
28157
  }
@@ -28358,7 +28361,7 @@ var EC2Provider = class {
28358
28361
  await this.ec2Client.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));
28359
28362
  this.logger.debug(`Cleaned up partially-created SecurityGroup ${logicalId} (${groupId}) after wiring failure`);
28360
28363
  } catch (cleanupError) {
28361
- this.logger.warn(`Failed to clean up partially-created SecurityGroup ${logicalId} (${groupId}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws ec2 delete-security-group --group-id ${groupId}`);
28364
+ this.logger.warn(`Failed to clean up partially-created SecurityGroup ${logicalId} (${groupId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws ec2 delete-security-group --group-id ${groupId}`);
28362
28365
  }
28363
28366
  throw innerError;
28364
28367
  }
@@ -28482,7 +28485,7 @@ var EC2Provider = class {
28482
28485
  this.logger.debug(`SecurityGroup ${physicalId} does not exist, skipping deletion`);
28483
28486
  return;
28484
28487
  }
28485
- const msg = error instanceof Error ? error.message : String(error);
28488
+ const msg = describeAwsFailure(error).detail;
28486
28489
  if (msg.includes("dependent object") && attempt < maxAttempts) {
28487
28490
  await this.cleanupSecurityGroupLambdaEnis(physicalId);
28488
28491
  this.logger.debug(`SecurityGroup ${physicalId} has dependent objects (attempt ${attempt}/${maxAttempts}), retrying in ${attempt * 5}s...`);
@@ -28512,7 +28515,7 @@ var EC2Provider = class {
28512
28515
  status: ni.Status ?? "unknown"
28513
28516
  }));
28514
28517
  } catch (err) {
28515
- this.logger.debug(`cleanupSecurityGroupLambdaEnis: DescribeNetworkInterfaces failed for ${groupId}: ${err instanceof Error ? err.message : String(err)}`);
28518
+ this.logger.debug(`cleanupSecurityGroupLambdaEnis: DescribeNetworkInterfaces failed for ${groupId}: ${describeAwsFailure(err).detail}`);
28516
28519
  return;
28517
28520
  }
28518
28521
  if (enis.length === 0) return;
@@ -28521,7 +28524,7 @@ var EC2Provider = class {
28521
28524
  await this.ec2Client.send(new DeleteNetworkInterfaceCommand({ NetworkInterfaceId: eni.id }));
28522
28525
  this.logger.debug(`cleanupSecurityGroupLambdaEnis: deleted Lambda ENI ${eni.id} for SG ${groupId}`);
28523
28526
  } catch (err) {
28524
- this.logger.debug(`cleanupSecurityGroupLambdaEnis: ENI ${eni.id} (status=${eni.status}) not yet deletable: ${err instanceof Error ? err.message : String(err)}`);
28527
+ this.logger.debug(`cleanupSecurityGroupLambdaEnis: ENI ${eni.id} (status=${eni.status}) not yet deletable: ${describeAwsFailure(err).detail}`);
28525
28528
  }
28526
28529
  }));
28527
28530
  }
@@ -28583,7 +28586,7 @@ var EC2Provider = class {
28583
28586
  }
28584
28587
  continue;
28585
28588
  }
28586
- this.logger.debug(`DescribeSecurityGroups for SecurityGroup ${groupId} failed (${errorClass}); omitting the VpcId attribute: ${error instanceof Error ? error.message : String(error)}`);
28589
+ this.logger.debug(`DescribeSecurityGroups for SecurityGroup ${groupId} failed (${errorClass}); omitting the VpcId attribute: ${describeAwsFailure(error).detail}`);
28587
28590
  return;
28588
28591
  }
28589
28592
  }
@@ -28720,7 +28723,7 @@ var EC2Provider = class {
28720
28723
  }
28721
28724
  return ids[0];
28722
28725
  } catch (error) {
28723
- this.logger.debug(`SecurityGroupIngress ${logicalId}: could not look up the existing rule id on ${groupId} (${error instanceof Error ? error.message : String(error)}) — not recording an Id attribute`);
28726
+ this.logger.debug(`SecurityGroupIngress ${logicalId}: could not look up the existing rule id on ${groupId} (${describeAwsFailure(error).detail}) — not recording an Id attribute`);
28724
28727
  return;
28725
28728
  }
28726
28729
  }
@@ -28843,7 +28846,7 @@ var EC2Provider = class {
28843
28846
  runInstancesToken.release();
28844
28847
  this.logger.debug(`Terminate requested for partially-created EC2 Instance ${logicalId} (${instanceId}) after wiring failure (not waiting for terminated state)`);
28845
28848
  } catch (cleanupError) {
28846
- this.logger.warn(`Failed to terminate partially-created EC2 Instance ${logicalId} (${instanceId}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. THE INSTANCE IS STILL RUNNING AND BILLING. Manual termination required: aws ec2 terminate-instances --instance-ids ${instanceId}`);
28849
+ this.logger.warn(`Failed to terminate partially-created EC2 Instance ${logicalId} (${instanceId}): ${describeAwsFailure(cleanupError).detail}. THE INSTANCE IS STILL RUNNING AND BILLING. Manual termination required: aws ec2 terminate-instances --instance-ids ${instanceId}`);
28847
28850
  }
28848
28851
  throw innerError;
28849
28852
  }
@@ -28934,7 +28937,7 @@ var EC2Provider = class {
28934
28937
  associated = true;
28935
28938
  break;
28936
28939
  } catch (error) {
28937
- const msg = error instanceof Error ? error.message : String(error);
28940
+ const msg = describeAwsFailure(error).detail;
28938
28941
  if (msg.includes("IncorrectState") || msg.includes("already associated")) {
28939
28942
  this.logger.debug(`IAM instance profile already associated with instance ${instanceId} (${logicalId})`);
28940
28943
  associated = true;
@@ -28975,7 +28978,7 @@ var EC2Provider = class {
28975
28978
  Values: [instanceId]
28976
28979
  }] }))).IamInstanceProfileAssociations?.some((a) => a.State === "associated") ?? false;
28977
28980
  } catch (err) {
28978
- this.logger.debug(`DescribeIamInstanceProfileAssociations failed for ${instanceId}: ${err instanceof Error ? err.message : String(err)}`);
28981
+ this.logger.debug(`DescribeIamInstanceProfileAssociations failed for ${instanceId}: ${describeAwsFailure(err).detail}`);
28979
28982
  return false;
28980
28983
  }
28981
28984
  }
@@ -29078,7 +29081,7 @@ var EC2Provider = class {
29078
29081
  this.logger.debug(`EC2 Instance ${physicalId} already terminated (not found), treating as success`);
29079
29082
  return;
29080
29083
  }
29081
- const msg = error instanceof Error ? error.message : String(error);
29084
+ const msg = describeAwsFailure(error).detail;
29082
29085
  if (removeProtection && isTerminationProtectionPropagationError(msg) && attempt < maxTerminateAttempts) {
29083
29086
  this.logger.debug(`Terminate of EC2 Instance ${logicalId} raced the DisableApiTermination flip-off (attempt ${attempt}/${maxTerminateAttempts}); re-flipping and retrying`);
29084
29087
  await disableInstanceApiTermination(this.ec2Client, physicalId, this.logger);
@@ -29525,7 +29528,7 @@ var EC2Provider = class {
29525
29528
  }));
29526
29529
  this.logger.debug(`Applied ${tags.length} tag(s) to ${logicalId}`);
29527
29530
  } catch (error) {
29528
- this.logger.warn(`Failed to apply tags to ${logicalId}: ${error instanceof Error ? error.message : String(error)}`);
29531
+ this.logger.warn(`Failed to apply tags to ${logicalId}: ${describeAwsFailure(error).detail}`);
29529
29532
  }
29530
29533
  }
29531
29534
  /**
@@ -29556,7 +29559,7 @@ var EC2Provider = class {
29556
29559
  }));
29557
29560
  this.logger.debug(`Removed ${tagsToRemove.length} tag(s) from ${resourceId}`);
29558
29561
  } catch (error) {
29559
- this.logger.warn(`Failed to remove tags from ${resourceId}: ${error instanceof Error ? error.message : String(error)}`);
29562
+ this.logger.warn(`Failed to remove tags from ${resourceId}: ${describeAwsFailure(error).detail}`);
29560
29563
  }
29561
29564
  if (tagsToAdd.length > 0) try {
29562
29565
  await this.ec2Client.send(new CreateTagsCommand({
@@ -29565,7 +29568,7 @@ var EC2Provider = class {
29565
29568
  }));
29566
29569
  this.logger.debug(`Added/updated ${tagsToAdd.length} tag(s) on ${resourceId}`);
29567
29570
  } catch (error) {
29568
- this.logger.warn(`Failed to add tags on ${resourceId}: ${error instanceof Error ? error.message : String(error)}`);
29571
+ this.logger.warn(`Failed to add tags on ${resourceId}: ${describeAwsFailure(error).detail}`);
29569
29572
  }
29570
29573
  }
29571
29574
  /**
@@ -29622,7 +29625,7 @@ var EC2Provider = class {
29622
29625
  if (elapsed >= totalBudgetMs) throw error;
29623
29626
  attempt += 1;
29624
29627
  const sleepMs = Math.min(delay, totalBudgetMs - elapsed);
29625
- const message = error instanceof Error ? error.message : String(error);
29628
+ const message = describeAwsFailure(error).detail;
29626
29629
  this.logger.debug(`${opts.description}: dependency still mapped (attempt ${attempt}, retrying in ${sleepMs}ms): ${message}`);
29627
29630
  await this.sleep(sleepMs);
29628
29631
  delay = Math.min(delay * 2, maxDelayMs);
@@ -30003,7 +30006,7 @@ var EC2Provider = class {
30003
30006
  }] }))).IamInstanceProfileAssociations?.find((a) => a.State === "associated" || a.State === "associating");
30004
30007
  if (live?.IamInstanceProfile?.Arn !== void 0) result["IamInstanceProfile"] = live.IamInstanceProfile.Arn;
30005
30008
  } catch (error) {
30006
- this.logger.warn(`Could not backfill IamInstanceProfile for ${physicalId} during the --no-wait capture (${error instanceof Error ? error.message : String(error)}); the field is omitted from the observed snapshot`);
30009
+ this.logger.warn(`Could not backfill IamInstanceProfile for ${physicalId} during the --no-wait capture (${describeAwsFailure(error).detail}); the field is omitted from the observed snapshot`);
30007
30010
  }
30008
30011
  const volumeIds = (instance.BlockDeviceMappings ?? []).filter((m) => m.Ebs?.VolumeId !== void 0).map((m) => m.Ebs.VolumeId);
30009
30012
  let volumesById = /* @__PURE__ */ new Map();
@@ -30011,7 +30014,7 @@ var EC2Provider = class {
30011
30014
  const volResp = await this.ec2Client.send(new DescribeVolumesCommand({ VolumeIds: volumeIds }));
30012
30015
  for (const v of volResp.Volumes ?? []) if (v.VolumeId !== void 0) volumesById.set(v.VolumeId, v);
30013
30016
  } catch (err) {
30014
- this.logger.debug(`DescribeVolumes(${volumeIds.join(",")}) failed: ${err instanceof Error ? err.message : String(err)}`);
30017
+ this.logger.debug(`DescribeVolumes(${volumeIds.join(",")}) failed: ${describeAwsFailure(err).detail}`);
30015
30018
  volumesById = /* @__PURE__ */ new Map();
30016
30019
  }
30017
30020
  const blockMappings = [];
@@ -30044,13 +30047,13 @@ var EC2Provider = class {
30044
30047
  }));
30045
30048
  if (attrResp.DisableApiTermination?.Value !== void 0) result["DisableApiTermination"] = attrResp.DisableApiTermination.Value;
30046
30049
  } catch (err) {
30047
- this.logger.debug(`DescribeInstanceAttribute(disableApiTermination, ${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
30050
+ this.logger.debug(`DescribeInstanceAttribute(disableApiTermination, ${physicalId}) failed: ${describeAwsFailure(err).detail}`);
30048
30051
  }
30049
30052
  try {
30050
30053
  const cpuCredits = (await this.ec2Client.send(new DescribeInstanceCreditSpecificationsCommand({ InstanceIds: [physicalId] }))).InstanceCreditSpecifications?.[0]?.CpuCredits;
30051
30054
  if (cpuCredits !== void 0) result["CreditSpecification"] = { CPUCredits: cpuCredits };
30052
30055
  } catch (err) {
30053
- this.logger.debug(`DescribeInstanceCreditSpecifications(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
30056
+ this.logger.debug(`DescribeInstanceCreditSpecifications(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
30054
30057
  }
30055
30058
  return result;
30056
30059
  }
@@ -30818,7 +30821,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
30818
30821
  await this.apiGatewayClient.send(new UpdateAccountCommand({ patchOperations }));
30819
30822
  return;
30820
30823
  } catch (error) {
30821
- const message = error instanceof Error ? error.message : String(error);
30824
+ const message = describeAwsFailure(error).detail;
30822
30825
  if ((message.toLowerCase().includes("not authorized") || message.toLowerCase().includes("does not have required permissions") || message.toLowerCase().includes("the role arn does not have required trust") || message.toLowerCase().includes("too many requests")) && attempt < ApiGatewayProvider.MAX_IAM_RETRIES) {
30823
30826
  this.logger.warn(`IAM propagation delay for ${logicalId} (attempt ${attempt}/${ApiGatewayProvider.MAX_IAM_RETRIES}), retrying in ${ApiGatewayProvider.IAM_RETRY_DELAY_MS / 1e3}s...`);
30824
30827
  await this.sleep(ApiGatewayProvider.IAM_RETRY_DELAY_MS);
@@ -31029,8 +31032,8 @@ var ApiGatewayProvider = class ApiGatewayProvider {
31029
31032
  try {
31030
31033
  await this.deleteResource(logicalId, physicalId, resourceType, previousProperties);
31031
31034
  } catch (error) {
31032
- orphanReason = `old API Gateway Resource ${physicalId} could not be deleted: ${String(error)}`;
31033
- this.logger.warn(`Failed to delete old API Gateway Resource ${physicalId} during replacement: ${String(error)}. The old resource may be orphaned and require manual cleanup.`);
31035
+ orphanReason = `old API Gateway Resource ${physicalId} could not be deleted: ${safeStringify(error)}`;
31036
+ this.logger.warn(`Failed to delete old API Gateway Resource ${physicalId} during replacement: ${safeStringify(error)}. The old resource may be orphaned and require manual cleanup.`);
31034
31037
  }
31035
31038
  const base = {
31036
31039
  physicalId: createResult.physicalId,
@@ -31205,7 +31208,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
31205
31208
  stageName
31206
31209
  }));
31207
31210
  } catch (cleanupError) {
31208
- this.logger.warn(`Failed to clean up stage ${stageName} after a post-create patch failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
31211
+ this.logger.warn(`Failed to clean up stage ${stageName} after a post-create patch failure: ${describeAwsFailure(cleanupError).detail}`);
31209
31212
  }
31210
31213
  throw patchError;
31211
31214
  }
@@ -31552,7 +31555,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
31552
31555
  }));
31553
31556
  this.logger.debug(`Cleaned up partially-created API Gateway Method ${logicalId} (${restApiId}/${resourceId}/${httpMethod}) after wiring failure`);
31554
31557
  } catch (cleanupError) {
31555
- this.logger.warn(`Failed to clean up partially-created API Gateway Method ${logicalId} (${restApiId}/${resourceId}/${httpMethod}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws apigateway delete-method --rest-api-id ${restApiId} --resource-id ${resourceId} --http-method ${httpMethod}`);
31558
+ this.logger.warn(`Failed to clean up partially-created API Gateway Method ${logicalId} (${restApiId}/${resourceId}/${httpMethod}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws apigateway delete-method --rest-api-id ${restApiId} --resource-id ${resourceId} --http-method ${httpMethod}`);
31556
31559
  }
31557
31560
  throw innerError;
31558
31561
  }
@@ -34564,7 +34567,7 @@ var CloudFrontDistributionProvider = class {
34564
34567
  if (cfnTags.length > 0) result["Tags"] = cfnTags;
34565
34568
  }
34566
34569
  } catch (error) {
34567
- this.logger.debug(`Tag read for CloudFront Distribution ${physicalId} failed during drift read: ${error instanceof Error ? error.message : String(error)}`);
34570
+ this.logger.debug(`Tag read for CloudFront Distribution ${physicalId} failed during drift read: ${describeAwsFailure(error).detail}`);
34568
34571
  }
34569
34572
  return result;
34570
34573
  }
@@ -34674,7 +34677,7 @@ var CloudFrontDistributionProvider = class {
34674
34677
  response = await this.cloudFrontClient.send(new GetDistributionCommand({ Id: distributionId }));
34675
34678
  } catch (error) {
34676
34679
  if (error instanceof NoSuchDistribution) throw error;
34677
- this.logger.debug(`Distribution ${distributionId} status read failed (${error instanceof Error ? error.message : String(error)}); retrying`);
34680
+ this.logger.debug(`Distribution ${distributionId} status read failed (${describeAwsFailure(error).detail}); retrying`);
34678
34681
  }
34679
34682
  if (response) {
34680
34683
  const status = response.Distribution?.Status;
@@ -35567,7 +35570,7 @@ var AgentCoreRuntimeProvider = class {
35567
35570
  attributes: this.buildAttributes(resp, resp.agentRuntimeName)
35568
35571
  };
35569
35572
  } catch (err) {
35570
- this.logger.debug(`Could not enrich imported BedrockAgentCore Runtime ${physicalId} attributes (${err instanceof Error ? err.message : String(err)}); recording AgentRuntimeId only (Fn::GetAtt resolves live via getAttribute)`);
35573
+ this.logger.debug(`Could not enrich imported BedrockAgentCore Runtime ${physicalId} attributes (${describeAwsFailure(err).detail}); recording AgentRuntimeId only (Fn::GetAtt resolves live via getAttribute)`);
35571
35574
  return {
35572
35575
  physicalId,
35573
35576
  attributes: { AgentRuntimeId: physicalId }
@@ -36041,7 +36044,7 @@ var AgentCoreEvaluatorProvider = class {
36041
36044
  try {
36042
36045
  result["Tags"] = tagMapToCfnList((await this.client.send(new ListTagsForResourceCommand$6({ resourceArn: physicalId }))).tags ?? {});
36043
36046
  } catch (err) {
36044
- this.logger.debug(`Failed to read tags for evaluator ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
36047
+ this.logger.debug(`Failed to read tags for evaluator ${physicalId}: ${describeAwsFailure(err).detail}`);
36045
36048
  }
36046
36049
  return result;
36047
36050
  }
@@ -36983,7 +36986,7 @@ var ECSProvider = class {
36983
36986
  }));
36984
36987
  this.logger.warn(`Deleted partially-created ECS service ${logicalId} (${service.serviceArn}) after the steady-state wait failed, so the next deploy's CreateService does not collide on the name. Its stopped tasks remain inspectable for about an hour: aws ecs list-tasks${clusterArg} --desired-status STOPPED`);
36985
36988
  } catch (cleanupError) {
36986
- this.logger.warn(`Failed to clean up partially-created ECS service ${logicalId} (${service.serviceArn}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws ecs delete-service${clusterArg} --service ${service.serviceArn} --force`);
36989
+ this.logger.warn(`Failed to clean up partially-created ECS service ${logicalId} (${service.serviceArn}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: aws ecs delete-service${clusterArg} --service ${service.serviceArn} --force`);
36987
36990
  }
36988
36991
  throw new Error(`ECS service ${logicalId} did not reach steady state under --full-wait: ${waitError instanceof Error ? waitError.message : String(waitError)}. Inspect why its tasks stopped (stopped tasks stay visible for about an hour): aws ecs list-tasks${clusterArg} --desired-status STOPPED, then aws ecs describe-tasks${clusterArg} --tasks <task-arn> --query 'tasks[].[stoppedReason,containers[].reason]'`, { cause: waitError });
36989
36992
  }
@@ -38863,7 +38866,7 @@ var ELBv2Provider = class {
38863
38866
  try {
38864
38867
  zones = (await this.getClient().send(new DescribeCapacityReservationCommand({ LoadBalancerArn: lbArn }))).CapacityReservationState ?? [];
38865
38868
  } catch (probeError) {
38866
- this.logger.debug(`DescribeCapacityReservation for ${logicalId} failed transiently (attempt ${attempt + 1}/${maxAttempts}): ${probeError instanceof Error ? probeError.message : String(probeError)}`);
38869
+ this.logger.debug(`DescribeCapacityReservation for ${logicalId} failed transiently (attempt ${attempt + 1}/${maxAttempts}): ${describeAwsFailure(probeError).detail}`);
38867
38870
  await capacityReservationDelays.sleep(intervalMs);
38868
38871
  continue;
38869
38872
  }
@@ -38889,7 +38892,7 @@ var ELBv2Provider = class {
38889
38892
  }));
38890
38893
  this.logger.debug(`Disabled deletion_protection.enabled on LoadBalancer ${logicalId} before delete`);
38891
38894
  } catch (flipError) {
38892
- if (!this.isNotFoundError(flipError)) this.logger.debug(`Could not disable deletion_protection.enabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
38895
+ if (!this.isNotFoundError(flipError)) this.logger.debug(`Could not disable deletion_protection.enabled on ${physicalId}: ${describeAwsFailure(flipError).detail}`);
38893
38896
  }
38894
38897
  try {
38895
38898
  await this.getClient().send(new DeleteLoadBalancerCommand({ LoadBalancerArn: physicalId }));
@@ -39593,7 +39596,7 @@ var ELBv2Provider = class {
39593
39596
  }
39594
39597
  result["Targets"] = targets;
39595
39598
  } catch (err) {
39596
- this.logger.debug(`ELBv2 DescribeTargetHealth(${targetGroupArn}) failed: ${err instanceof Error ? err.message : String(err)}`);
39599
+ this.logger.debug(`ELBv2 DescribeTargetHealth(${targetGroupArn}) failed: ${describeAwsFailure(err).detail}`);
39597
39600
  }
39598
39601
  }
39599
39602
  /**
@@ -39681,7 +39684,7 @@ var ELBv2Provider = class {
39681
39684
  const tagDesc = (await this.getClient().send(new DescribeTagsCommand({ ResourceArns: [arn] }))).TagDescriptions?.[0];
39682
39685
  result["Tags"] = normalizeAwsTagsToCfn(tagDesc?.Tags);
39683
39686
  } catch (err) {
39684
- this.logger.debug(`ELBv2 DescribeTags(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`);
39687
+ this.logger.debug(`ELBv2 DescribeTags(${arn}) failed: ${describeAwsFailure(err).detail}`);
39685
39688
  }
39686
39689
  }
39687
39690
  /**
@@ -39983,7 +39986,7 @@ var RDSProvider = class {
39983
39986
  ApplyImmediately: true
39984
39987
  }));
39985
39988
  } catch (disableError) {
39986
- this.logger.debug(`Could not disable DeletionProtection on partially-created DBCluster ${dbClusterIdentifier}: ${disableError instanceof Error ? disableError.message : String(disableError)} (proceeding with DeleteDBCluster anyway)`);
39989
+ this.logger.debug(`Could not disable DeletionProtection on partially-created DBCluster ${dbClusterIdentifier}: ${describeAwsFailure(disableError).detail} (proceeding with DeleteDBCluster anyway)`);
39987
39990
  }
39988
39991
  await this.getClient().send(new DeleteDBClusterCommand({
39989
39992
  DBClusterIdentifier: dbClusterIdentifier,
@@ -39991,7 +39994,7 @@ var RDSProvider = class {
39991
39994
  }));
39992
39995
  this.logger.debug(`Delete requested for partially-created DBCluster ${logicalId} (${dbClusterIdentifier}) after wiring failure (not waiting for deleted state)`);
39993
39996
  } catch (cleanupError) {
39994
- this.logger.warn(`Failed to delete partially-created DBCluster ${logicalId} (${dbClusterIdentifier}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. THE CLUSTER IS STILL RUNNING AND BILLING. Manual cleanup required: ${wantsDeletionProtection ? `aws rds modify-db-cluster --db-cluster-identifier ${dbClusterIdentifier} --no-deletion-protection --apply-immediately; ` : ""}aws rds delete-db-cluster --db-cluster-identifier ${dbClusterIdentifier} --skip-final-snapshot`);
39997
+ this.logger.warn(`Failed to delete partially-created DBCluster ${logicalId} (${dbClusterIdentifier}): ${describeAwsFailure(cleanupError).detail}. THE CLUSTER IS STILL RUNNING AND BILLING. Manual cleanup required: ${wantsDeletionProtection ? `aws rds modify-db-cluster --db-cluster-identifier ${dbClusterIdentifier} --no-deletion-protection --apply-immediately; ` : ""}aws rds delete-db-cluster --db-cluster-identifier ${dbClusterIdentifier} --skip-final-snapshot`);
39995
39998
  }
39996
39999
  throw innerError;
39997
40000
  }
@@ -40058,7 +40061,7 @@ var RDSProvider = class {
40058
40061
  }));
40059
40062
  this.logger.debug(`Disabled DeletionProtection on DBCluster ${logicalId} before delete`);
40060
40063
  } catch (disableError) {
40061
- if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`);
40064
+ if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${describeAwsFailure(disableError).detail}`);
40062
40065
  }
40063
40066
  const finalSnapshotId = context?.finalSnapshotIdentifier;
40064
40067
  await this.getClient().send(new DeleteDBClusterCommand({
@@ -40186,7 +40189,7 @@ var RDSProvider = class {
40186
40189
  }));
40187
40190
  this.logger.debug(`Disabled DeletionProtection on DBInstance ${logicalId} before delete`);
40188
40191
  } catch (disableError) {
40189
- if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`);
40192
+ if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${describeAwsFailure(disableError).detail}`);
40190
40193
  }
40191
40194
  const finalSnapshotId = properties?.["DBClusterIdentifier"] === void 0 ? context?.finalSnapshotIdentifier : void 0;
40192
40195
  await this.getClient().send(new DeleteDBInstanceCommand({
@@ -40476,7 +40479,7 @@ var RDSProvider = class {
40476
40479
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$10({ ResourceName: arn }));
40477
40480
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagList);
40478
40481
  } catch (err) {
40479
- this.logger.debug(`RDS ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`);
40482
+ this.logger.debug(`RDS ListTagsForResource(${arn}) failed: ${describeAwsFailure(err).detail}`);
40480
40483
  }
40481
40484
  }
40482
40485
  async importDBInstance(input) {
@@ -40776,7 +40779,7 @@ var RDSDBProxyProvider = class {
40776
40779
  const tagResp = await client.send(new ListTagsForResourceCommand$10({ ResourceName: p.DBProxyArn }));
40777
40780
  result["Tags"] = normalizeAwsTagsToCfn(tagResp.TagList ?? []);
40778
40781
  } catch (error) {
40779
- this.logger.debug(`ListTagsForResource failed for ${physicalId}: ${error instanceof Error ? error.message : String(error)}`);
40782
+ this.logger.debug(`ListTagsForResource failed for ${physicalId}: ${describeAwsFailure(error).detail}`);
40780
40783
  result["Tags"] = [];
40781
40784
  }
40782
40785
  else result["Tags"] = [];
@@ -40793,7 +40796,7 @@ var RDSDBProxyProvider = class {
40793
40796
  arn = (await client.send(new DescribeDBProxiesCommand({ DBProxyName: physicalId }))).DBProxies?.[0]?.DBProxyArn;
40794
40797
  if (arn) this.attributeCache.set(arnCacheKey, arn);
40795
40798
  } catch (error) {
40796
- this.logger.debug(`Skipping tag diff for ${physicalId} (no ARN): ${error instanceof Error ? error.message : String(error)}`);
40799
+ this.logger.debug(`Skipping tag diff for ${physicalId} (no ARN): ${describeAwsFailure(error).detail}`);
40797
40800
  return;
40798
40801
  }
40799
40802
  if (!arn) return;
@@ -41087,7 +41090,7 @@ var RDSDBProxyEndpointProvider = class {
41087
41090
  const tagResp = await client.send(new ListTagsForResourceCommand$10({ ResourceName: e.DBProxyEndpointArn }));
41088
41091
  result["Tags"] = normalizeAwsTagsToCfn(tagResp.TagList ?? []);
41089
41092
  } catch (error) {
41090
- this.logger.debug(`ListTagsForResource failed for ${physicalId}: ${error instanceof Error ? error.message : String(error)}`);
41093
+ this.logger.debug(`ListTagsForResource failed for ${physicalId}: ${describeAwsFailure(error).detail}`);
41091
41094
  result["Tags"] = [];
41092
41095
  }
41093
41096
  else result["Tags"] = [];
@@ -41104,7 +41107,7 @@ var RDSDBProxyEndpointProvider = class {
41104
41107
  arn = (await client.send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: physicalId }))).DBProxyEndpoints?.[0]?.DBProxyEndpointArn;
41105
41108
  if (arn) this.attributeCache.set(arnCacheKey, arn);
41106
41109
  } catch (error) {
41107
- this.logger.debug(`Skipping tag diff for ${physicalId} (no ARN): ${error instanceof Error ? error.message : String(error)}`);
41110
+ this.logger.debug(`Skipping tag diff for ${physicalId} (no ARN): ${describeAwsFailure(error).detail}`);
41108
41111
  return;
41109
41112
  }
41110
41113
  if (!arn) return;
@@ -41730,7 +41733,7 @@ var DocDBProvider = class {
41730
41733
  }));
41731
41734
  this.logger.debug(`Disabled DeletionProtection on DocDB DBCluster ${logicalId} before delete`);
41732
41735
  } catch (disableError) {
41733
- if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`);
41736
+ if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${describeAwsFailure(disableError).detail}`);
41734
41737
  }
41735
41738
  const finalSnapshotId = context?.finalSnapshotIdentifier;
41736
41739
  await this.getClient().send(new DeleteDBClusterCommand$1({
@@ -42069,7 +42072,7 @@ var DocDBProvider = class {
42069
42072
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$12({ ResourceName: arn }));
42070
42073
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagList);
42071
42074
  } catch (err) {
42072
- this.logger.debug(`DocDB ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`);
42075
+ this.logger.debug(`DocDB ListTagsForResource(${arn}) failed: ${describeAwsFailure(err).detail}`);
42073
42076
  }
42074
42077
  }
42075
42078
  async importDBInstance(input) {
@@ -42367,7 +42370,7 @@ var NeptuneProvider = class {
42367
42370
  }));
42368
42371
  this.logger.debug(`Disabled DeletionProtection on Neptune DBCluster ${logicalId} before delete`);
42369
42372
  } catch (disableError) {
42370
- if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`);
42373
+ if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${describeAwsFailure(disableError).detail}`);
42371
42374
  }
42372
42375
  const finalSnapshotId = context?.finalSnapshotIdentifier;
42373
42376
  await this.getClient().send(new DeleteDBClusterCommand$2({
@@ -42467,7 +42470,7 @@ var NeptuneProvider = class {
42467
42470
  }));
42468
42471
  this.logger.debug(`Disabled DeletionProtection on Neptune DBInstance ${logicalId} before delete`);
42469
42472
  } catch (disableError) {
42470
- if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`);
42473
+ if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) this.logger.debug(`Could not disable deletion protection for ${physicalId}: ${describeAwsFailure(disableError).detail}`);
42471
42474
  }
42472
42475
  await this.getClient().send(new DeleteDBInstanceCommand$2({
42473
42476
  DBInstanceIdentifier: physicalId,
@@ -42712,7 +42715,7 @@ var NeptuneProvider = class {
42712
42715
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$13({ ResourceName: arn }));
42713
42716
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagList);
42714
42717
  } catch (err) {
42715
- this.logger.debug(`Neptune ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`);
42718
+ this.logger.debug(`Neptune ListTagsForResource(${arn}) failed: ${describeAwsFailure(err).detail}`);
42716
42719
  }
42717
42720
  }
42718
42721
  async importDBInstance(input) {
@@ -43038,7 +43041,7 @@ var Route53Provider = class {
43038
43041
  await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
43039
43042
  callerReferenceToken.release();
43040
43043
  } catch (deleteError) {
43041
- this.logger.warn(`Best-effort rollback DeleteHostedZone for ${zoneId} also failed: ${deleteError instanceof Error ? deleteError.message : String(deleteError)} — operator may need to clean up the orphan zone`);
43044
+ this.logger.warn(`Best-effort rollback DeleteHostedZone for ${zoneId} also failed: ${describeAwsFailure(deleteError).detail} — operator may need to clean up the orphan zone`);
43042
43045
  }
43043
43046
  const cause = uhfError instanceof Error ? uhfError : void 0;
43044
43047
  throw new ProvisioningError(`Failed to enable Accelerated Recovery on hosted zone ${logicalId} (${zoneId}): ${uhfError instanceof Error ? uhfError.message : String(uhfError)}`, resourceType, logicalId, zoneId, cause);
@@ -43568,7 +43571,7 @@ var Route53Provider = class {
43568
43571
  }));
43569
43572
  this.logger.debug(`Applied ${tags.length} tag(s) and removed ${removeTagKeys.length} tag(s) on hosted zone ${logicalId}`);
43570
43573
  } catch (error) {
43571
- const detail = error instanceof Error ? error.message : String(error);
43574
+ const detail = describeAwsFailure(error).detail;
43572
43575
  if (removeTagKeys.length > 0) throw new ProvisioningError(`Failed to remove tag(s) ${removeTagKeys.join(", ")} from hosted zone ${logicalId}: ${detail}. The removal will NOT be retried on the next deploy (state no longer records the tag), so it is reported instead of ignored.`, "AWS::Route53::HostedZone", logicalId, zoneId, error instanceof Error ? error : void 0);
43573
43576
  this.logger.warn(`Failed to apply tags to hosted zone ${logicalId}: ${detail}`);
43574
43577
  }
@@ -43631,7 +43634,7 @@ var Route53Provider = class {
43631
43634
  this.logger.debug(`Query logging config already exists for hosted zone ${logicalId}`);
43632
43635
  return;
43633
43636
  }
43634
- this.logger.warn(`Failed to apply query logging config to hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`);
43637
+ this.logger.warn(`Failed to apply query logging config to hosted zone ${logicalId}: ${describeAwsFailure(error).detail}`);
43635
43638
  }
43636
43639
  }
43637
43640
  /**
@@ -43676,7 +43679,7 @@ var Route53Provider = class {
43676
43679
  }
43677
43680
  } catch (error) {
43678
43681
  if (error instanceof Error && (error.name === "NoSuchHostedZone" || error.name === "NoSuchQueryLoggingConfig")) return;
43679
- this.logger.warn(`Failed to delete query logging config for hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`);
43682
+ this.logger.warn(`Failed to delete query logging config for hosted zone ${logicalId}: ${describeAwsFailure(error).detail}`);
43680
43683
  }
43681
43684
  }
43682
43685
  /**
@@ -43718,7 +43721,7 @@ var Route53Provider = class {
43718
43721
  }));
43719
43722
  }
43720
43723
  } catch (error) {
43721
- this.logger.warn(`Failed to sync VPC associations for hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`);
43724
+ this.logger.warn(`Failed to sync VPC associations for hosted zone ${logicalId}: ${describeAwsFailure(error).detail}`);
43722
43725
  }
43723
43726
  }
43724
43727
  /**
@@ -43768,7 +43771,7 @@ var Route53Provider = class {
43768
43771
  const sawLaterName = zones.some((z) => normalizeRecordName(z.Name ?? "") !== normalizedName);
43769
43772
  absenceIsSound = !hostedZoneName.includes("\\") && (narrowing ? sawLaterName || response.IsTruncated !== true : zones.length > 0 || response.IsTruncated !== true);
43770
43773
  } catch (error) {
43771
- lookupErrorMessage = error instanceof Error ? error.message : String(error);
43774
+ lookupErrorMessage = describeAwsFailure(error).detail;
43772
43775
  lookupErrorCause = error instanceof Error ? error : void 0;
43773
43776
  this.logger.warn(`Failed to resolve HostedZoneName "${hostedZoneName}" for ${logicalId}: ${lookupErrorMessage}`);
43774
43777
  }
@@ -43811,7 +43814,7 @@ var Route53Provider = class {
43811
43814
  type
43812
43815
  };
43813
43816
  } catch (err) {
43814
- this.logger.debug(`Cannot resolve record-set identity for '${physicalId}': ${err instanceof Error ? err.message : String(err)}`);
43817
+ this.logger.debug(`Cannot resolve record-set identity for '${physicalId}': ${describeAwsFailure(err).detail}`);
43815
43818
  return;
43816
43819
  }
43817
43820
  }
@@ -43878,14 +43881,14 @@ var Route53Provider = class {
43878
43881
  }));
43879
43882
  result["HostedZoneTags"] = normalizeAwsTagsToCfn(tagsResp.ResourceTagSet?.Tags);
43880
43883
  } catch (err) {
43881
- this.logger.debug(`Route53 ListTagsForResource(${idTail}) failed: ${err instanceof Error ? err.message : String(err)}`);
43884
+ this.logger.debug(`Route53 ListTagsForResource(${idTail}) failed: ${describeAwsFailure(err).detail}`);
43882
43885
  }
43883
43886
  try {
43884
43887
  const qlc = (await this.getClient().send(new ListQueryLoggingConfigsCommand({ HostedZoneId: idTail }))).QueryLoggingConfigs?.[0];
43885
43888
  if (qlc?.CloudWatchLogsLogGroupArn) result["QueryLoggingConfig"] = { CloudWatchLogsLogGroupArn: qlc.CloudWatchLogsLogGroupArn };
43886
43889
  else result["QueryLoggingConfig"] = {};
43887
43890
  } catch (err) {
43888
- this.logger.debug(`Route53 ListQueryLoggingConfigs(${idTail}) failed: ${err instanceof Error ? err.message : String(err)}`);
43891
+ this.logger.debug(`Route53 ListQueryLoggingConfigs(${idTail}) failed: ${describeAwsFailure(err).detail}`);
43889
43892
  result["QueryLoggingConfig"] = {};
43890
43893
  }
43891
43894
  return result;
@@ -44101,7 +44104,7 @@ var Route53Provider = class {
44101
44104
  try {
44102
44105
  observed = await this.readRecordSet(compositeId);
44103
44106
  } catch (err) {
44104
- return adoptVerbatim(`verification failed: ${err instanceof Error ? err.message : String(err)}`);
44107
+ return adoptVerbatim(`verification failed: ${describeAwsFailure(err).detail}`);
44105
44108
  }
44106
44109
  if (!observed) return adoptVerbatim("the record was not found under the resolved hosted zone");
44107
44110
  return {
@@ -44157,7 +44160,7 @@ var Route53Provider = class {
44157
44160
  };
44158
44161
  } catch (error) {
44159
44162
  if (error instanceof Error && error.name === "NoSuchHostedZone") return null;
44160
- this.logger.warn(`Imported hosted zone ${zoneId} but could not read its NameServers: ${error instanceof Error ? error.message : String(error)}. The zone is adopted without them (any attributes already in state for this zone are kept). Re-run \`cdkd import --resource ${logicalId}=${zoneId} --force\` once the permission is granted, or make a template change that forces an UPDATE — a plain \`cdkd deploy\` does NOT heal the record, because an unchanged zone is NO_CHANGE and never calls update().`);
44163
+ this.logger.warn(`Imported hosted zone ${zoneId} but could not read its NameServers: ${describeAwsFailure(error).detail}. The zone is adopted without them (any attributes already in state for this zone are kept). Re-run \`cdkd import --resource ${logicalId}=${zoneId} --force\` once the permission is granted, or make a template change that forces an UPDATE — a plain \`cdkd deploy\` does NOT heal the record, because an unchanged zone is NO_CHANGE and never calls update().`);
44161
44164
  return {};
44162
44165
  }
44163
44166
  }
@@ -45132,7 +45135,7 @@ var CognitoUserPoolProvider = class {
45132
45135
  await this.getClient().send(new DeleteUserPoolCommand({ UserPoolId: createdUserPoolId }));
45133
45136
  this.logger.debug(`Rolled back partially-created Cognito User Pool ${createdUserPoolId}`);
45134
45137
  } catch (rollbackError) {
45135
- this.logger.warn(`Failed to roll back partially-created Cognito User Pool ${createdUserPoolId}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
45138
+ this.logger.warn(`Failed to roll back partially-created Cognito User Pool ${createdUserPoolId}: ${describeAwsFailure(rollbackError).detail}`);
45136
45139
  }
45137
45140
  const cause = error instanceof Error ? error : void 0;
45138
45141
  throw new ProvisioningError(`Failed to create Cognito User Pool ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, poolName, cause);
@@ -45283,7 +45286,7 @@ var CognitoUserPoolProvider = class {
45283
45286
  failed: false
45284
45287
  } : { failed: false };
45285
45288
  } catch (error) {
45286
- this.logger.debug(`GetUserPoolMfaConfig failed for UserPool ${physicalId} (${error instanceof Error ? error.name : typeof error}): ${error instanceof Error ? error.message : String(error)}`);
45289
+ this.logger.debug(`GetUserPoolMfaConfig failed for UserPool ${physicalId} (${error instanceof Error ? error.name : typeof error}): ${describeAwsFailure(error).detail}`);
45287
45290
  return { failed: true };
45288
45291
  }
45289
45292
  }
@@ -45301,7 +45304,7 @@ var CognitoUserPoolProvider = class {
45301
45304
  for (let attempt = 1;; attempt++) try {
45302
45305
  return await fn();
45303
45306
  } catch (error) {
45304
- const msg = error instanceof Error ? error.message : String(error);
45307
+ const msg = describeAwsFailure(error).detail;
45305
45308
  if (!((error instanceof Error ? error.name : "") === "ConcurrentModificationException" || /concurrent modification|please retry|try again|in progress/i.test(msg)) || attempt >= maxAttempts) throw error;
45306
45309
  const delayMs = Math.min(1e3 * 2 ** (attempt - 1), 4e3);
45307
45310
  this.logger.debug(`Transient error on "${label}" (attempt ${attempt}/${maxAttempts}): ${msg} — retrying in ${delayMs}ms`);
@@ -45559,7 +45562,7 @@ var CognitoUserPoolProvider = class {
45559
45562
  DeletionProtection: "INACTIVE"
45560
45563
  }));
45561
45564
  } catch (flipError) {
45562
- this.logger.debug(`Could not disable DeletionProtection for ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
45565
+ this.logger.debug(`Could not disable DeletionProtection for ${physicalId}: ${describeAwsFailure(flipError).detail}`);
45563
45566
  }
45564
45567
  }
45565
45568
  }
@@ -45646,7 +45649,7 @@ var CognitoUserPoolProvider = class {
45646
45649
  result["WebAuthnRelyingPartyID"] = mfa.WebAuthnConfiguration?.RelyingPartyId ?? "";
45647
45650
  result["WebAuthnUserVerification"] = mfa.WebAuthnConfiguration?.UserVerification ?? "";
45648
45651
  } catch (mfaErr) {
45649
- this.logger.debug(`GetUserPoolMfaConfig failed for ${physicalId}, skipping MFA-derived drift keys: ${mfaErr instanceof Error ? mfaErr.message : String(mfaErr)}`);
45652
+ this.logger.debug(`GetUserPoolMfaConfig failed for ${physicalId}, skipping MFA-derived drift keys: ${describeAwsFailure(mfaErr).detail}`);
45650
45653
  }
45651
45654
  return result;
45652
45655
  }
@@ -46159,7 +46162,7 @@ var ElastiCacheProvider = class {
46159
46162
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$7({ ResourceName: arn }));
46160
46163
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagList);
46161
46164
  } catch (err) {
46162
- this.logger.debug(`ElastiCache ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`);
46165
+ this.logger.debug(`ElastiCache ListTagsForResource(${arn}) failed: ${describeAwsFailure(err).detail}`);
46163
46166
  }
46164
46167
  }
46165
46168
  /**
@@ -46598,7 +46601,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
46598
46601
  arn = nsResp.Namespace?.Arn;
46599
46602
  hostedZoneId = nsResp.Namespace?.Properties?.DnsProperties?.HostedZoneId;
46600
46603
  } catch (err) {
46601
- this.logger.debug(`GetNamespace(${namespaceId}) after create failed: ${err instanceof Error ? err.message : String(err)}`);
46604
+ this.logger.debug(`GetNamespace(${namespaceId}) after create failed: ${describeAwsFailure(err).detail}`);
46602
46605
  }
46603
46606
  if (!arn) arn = await this.buildNamespaceArn(namespaceId);
46604
46607
  this.logger.debug(`Successfully created public DNS namespace ${logicalId}: ${namespaceId}`);
@@ -46874,7 +46877,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
46874
46877
  const resp = await this.getClient().send(new GetNamespaceCommand({ Id: namespaceId }));
46875
46878
  if (resp.Namespace?.Arn) return resp.Namespace.Arn;
46876
46879
  } catch (err) {
46877
- this.logger.debug(`GetNamespace(${namespaceId}) failed while resolving ARN: ${err instanceof Error ? err.message : String(err)}`);
46880
+ this.logger.debug(`GetNamespace(${namespaceId}) failed while resolving ARN: ${describeAwsFailure(err).detail}`);
46878
46881
  }
46879
46882
  return this.buildNamespaceArn(namespaceId);
46880
46883
  }
@@ -47098,7 +47101,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
47098
47101
  try {
47099
47102
  result["ServiceAttributes"] = (await this.getClient().send(new GetServiceAttributesCommand({ ServiceId: physicalId }))).ServiceAttributes?.Attributes ?? {};
47100
47103
  } catch (err) {
47101
- this.logger.debug(`ServiceDiscovery GetServiceAttributes(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
47104
+ this.logger.debug(`ServiceDiscovery GetServiceAttributes(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
47102
47105
  }
47103
47106
  if (svc.Arn) await this.attachTags(result, svc.Arn);
47104
47107
  return result;
@@ -47126,7 +47129,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
47126
47129
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$14({ ResourceARN: arn }));
47127
47130
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
47128
47131
  } catch (err) {
47129
- this.logger.debug(`ServiceDiscovery ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`);
47132
+ this.logger.debug(`ServiceDiscovery ListTagsForResource(${arn}) failed: ${describeAwsFailure(err).detail}`);
47130
47133
  }
47131
47134
  }
47132
47135
  async import(input) {
@@ -47396,7 +47399,7 @@ var AppSyncProvider = class {
47396
47399
  try {
47397
47400
  return await this.buildAppSyncArn(suffix);
47398
47401
  } catch (error) {
47399
- this.logger.warn(`Created ${logicalId} (${physicalId}) but could not build its ARN attribute: ${error instanceof Error ? error.message : String(error)}. Ref will resolve to the compound physical id until the next update.`);
47402
+ this.logger.warn(`Created ${logicalId} (${physicalId}) but could not build its ARN attribute: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id until the next update.`);
47400
47403
  return;
47401
47404
  }
47402
47405
  }
@@ -47437,7 +47440,7 @@ var AppSyncProvider = class {
47437
47440
  return await this.buildAppSyncArn(suffix, regionOverride);
47438
47441
  } catch (error) {
47439
47442
  if (!omitArnOnFailure) throw error;
47440
- this.logger.warn(`Imported ${resourceType} (${physicalId}) but its ARN attribute was NOT recorded: ${error instanceof Error ? error.message : String(error)}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update heals the record.`);
47443
+ this.logger.warn(`Imported ${resourceType} (${physicalId}) but its ARN attribute was NOT recorded: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update heals the record.`);
47441
47444
  return;
47442
47445
  }
47443
47446
  };
@@ -47480,7 +47483,7 @@ var AppSyncProvider = class {
47480
47483
  try {
47481
47484
  attributes = await this.childRefAttributes(resourceType, physicalId);
47482
47485
  } catch (error) {
47483
- this.logger.warn(`Updated ${resourceType} (${physicalId}) but could not rebuild its ARN attribute: ${error instanceof Error ? error.message : String(error)}. The previously recorded attributes are kept.`);
47486
+ this.logger.warn(`Updated ${resourceType} (${physicalId}) but could not rebuild its ARN attribute: ${describeAwsFailure(error).detail}. The previously recorded attributes are kept.`);
47484
47487
  }
47485
47488
  return {
47486
47489
  physicalId,
@@ -47525,7 +47528,7 @@ var AppSyncProvider = class {
47525
47528
  try {
47526
47529
  return await this.childRefAttributes(resourceType, physicalId, region, true) ?? {};
47527
47530
  } catch (error) {
47528
- this.logger.warn(`Imported ${resourceType} (${physicalId}) but could not build its ARN attribute: ${error instanceof Error ? error.message : String(error)}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update heals the record.`);
47531
+ this.logger.warn(`Imported ${resourceType} (${physicalId}) but could not build its ARN attribute: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update heals the record.`);
47529
47532
  return {};
47530
47533
  }
47531
47534
  }
@@ -47992,7 +47995,7 @@ var AppSyncProvider = class {
47992
47995
  try {
47993
47996
  entries = requireConfigArray(value, "AWS::AppSync::GraphQLApi AdditionalAuthenticationProviders");
47994
47997
  } catch (error) {
47995
- const message = error instanceof Error ? error.message : String(error);
47998
+ const message = describeAwsFailure(error).detail;
47996
47999
  if (options?.onUnusable) {
47997
48000
  options.onUnusable(message);
47998
48001
  return;
@@ -48087,7 +48090,7 @@ var AppSyncProvider = class {
48087
48090
  desired = this.asObject(properties["EnvironmentVariables"], "EnvironmentVariables", { logicalId });
48088
48091
  } catch (error) {
48089
48092
  if (!isUpdate && !replayingState) throw error;
48090
- this.logger.warn(`AppSync GraphqlApi ${logicalId}: ${error instanceof Error ? error.message : String(error)} — leaving the live environment variables untouched`);
48093
+ this.logger.warn(`AppSync GraphqlApi ${logicalId}: ${describeAwsFailure(error).detail} — leaving the live environment variables untouched`);
48091
48094
  return;
48092
48095
  }
48093
48096
  let previous;
@@ -48396,7 +48399,7 @@ var AppSyncProvider = class {
48396
48399
  await this.getClient().send(new DeleteGraphqlApiCommand({ apiId: createdApiId }));
48397
48400
  this.logger.debug(`Rolled back partially-created GraphQL API ${createdApiId}`);
48398
48401
  } catch (rollbackError) {
48399
- this.logger.warn(`Failed to roll back partially-created GraphQL API ${createdApiId}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
48402
+ this.logger.warn(`Failed to roll back partially-created GraphQL API ${createdApiId}: ${describeAwsFailure(rollbackError).detail}`);
48400
48403
  }
48401
48404
  const cause = error instanceof Error ? error : void 0;
48402
48405
  throw new ProvisioningError(`Failed to create GraphQL API ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
@@ -48703,7 +48706,7 @@ var AppSyncProvider = class {
48703
48706
  try {
48704
48707
  return print(parse$1(sdl));
48705
48708
  } catch (err) {
48706
- this.logger.debug(`Failed to parse ${source} SDL via graphql-js (falling back to raw): ${err instanceof Error ? err.message : String(err)}`);
48709
+ this.logger.debug(`Failed to parse ${source} SDL via graphql-js (falling back to raw): ${describeAwsFailure(err).detail}`);
48707
48710
  return sdl;
48708
48711
  }
48709
48712
  }
@@ -48782,7 +48785,7 @@ var AppSyncProvider = class {
48782
48785
  const envResp = await this.getClient().send(new GetGraphqlApiEnvironmentVariablesCommand({ apiId: physicalId }));
48783
48786
  if (envResp.environmentVariables !== void 0) result["EnvironmentVariables"] = envResp.environmentVariables;
48784
48787
  } catch (err) {
48785
- this.logger.warn(`Could not read AppSync GraphqlApi ${physicalId} environment variables (drift on that property will not be reported): ${err instanceof Error ? err.message : String(err)}`);
48788
+ this.logger.warn(`Could not read AppSync GraphqlApi ${physicalId} environment variables (drift on that property will not be reported): ${describeAwsFailure(err).detail}`);
48786
48789
  }
48787
48790
  return result;
48788
48791
  }
@@ -50158,7 +50161,7 @@ var GlueWorkflowProvider = class {
50158
50161
  const tagResp = await this.getClient().send(new GetTagsCommand({ ResourceArn: arn }));
50159
50162
  tags = normalizeAwsTagsToCfn(tagResp.Tags);
50160
50163
  } catch (err) {
50161
- this.logger.debug(`GetTags failed for Glue Workflow ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
50164
+ this.logger.debug(`GetTags failed for Glue Workflow ${physicalId}: ${describeAwsFailure(err).detail}`);
50162
50165
  }
50163
50166
  result["Tags"] = tags;
50164
50167
  return result;
@@ -50525,7 +50528,7 @@ async function fetchGlueTags(client, stsClient, resource, name, accountId, logge
50525
50528
  const resp = await client.send(new GetTagsCommand({ ResourceArn: arn }));
50526
50529
  return normalizeAwsTagsToCfn(resp.Tags);
50527
50530
  } catch (err) {
50528
- logger.debug(`GetTags failed for ${resource}/${name}: ${err instanceof Error ? err.message : String(err)}`);
50531
+ logger.debug(`GetTags failed for ${resource}/${name}: ${describeAwsFailure(err).detail}`);
50529
50532
  return [];
50530
50533
  }
50531
50534
  }
@@ -51058,7 +51061,7 @@ var GlueCrawlerProvider = class {
51058
51061
  try {
51059
51062
  await this.getClient().send(new StopCrawlerCommand({ Name: physicalId }));
51060
51063
  } catch (err) {
51061
- this.logger.debug(`StopCrawler for ${physicalId} returned ${err instanceof Error ? err.name : String(err)}; continuing to wait`);
51064
+ this.logger.debug(`StopCrawler for ${physicalId} returned ${err instanceof Error ? err.name : safeStringify(err)}; continuing to wait`);
51062
51065
  }
51063
51066
  for (let attempt = 0; attempt < CRAWLER_STOP_MAX_ATTEMPTS; attempt++) {
51064
51067
  try {
@@ -51493,7 +51496,7 @@ var GlueTriggerProvider = class {
51493
51496
  await this.waitForTriggerDeactivated(physicalId);
51494
51497
  }
51495
51498
  } catch (err) {
51496
- if (!(err instanceof EntityNotFoundException)) this.logger.debug(`GetTrigger pre-check failed for ${physicalId}; continuing anyway: ${err instanceof Error ? err.message : String(err)}`);
51499
+ if (!(err instanceof EntityNotFoundException)) this.logger.debug(`GetTrigger pre-check failed for ${physicalId}; continuing anyway: ${describeAwsFailure(err).detail}`);
51497
51500
  }
51498
51501
  const update = {
51499
51502
  ...properties["Description"] !== void 0 && { Description: properties["Description"] },
@@ -51556,7 +51559,7 @@ var GlueTriggerProvider = class {
51556
51559
  await this.waitForTriggerDeactivated(physicalId);
51557
51560
  }
51558
51561
  } catch (err) {
51559
- if (!(err instanceof EntityNotFoundException)) this.logger.debug(`GetTrigger pre-delete check failed for ${physicalId}; continuing: ${err instanceof Error ? err.message : String(err)}`);
51562
+ if (!(err instanceof EntityNotFoundException)) this.logger.debug(`GetTrigger pre-delete check failed for ${physicalId}; continuing: ${describeAwsFailure(err).detail}`);
51560
51563
  }
51561
51564
  await this.getClient().send(new DeleteTriggerCommand({ Name: physicalId }));
51562
51565
  } catch (error) {
@@ -53115,7 +53118,7 @@ var KinesisStreamProvider = class {
53115
53118
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
53116
53119
  } catch (err) {
53117
53120
  if (err instanceof ResourceNotFoundException$10) return void 0;
53118
- this.logger.debug(`Kinesis ListTagsForStream(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
53121
+ this.logger.debug(`Kinesis ListTagsForStream(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
53119
53122
  }
53120
53123
  return result;
53121
53124
  }
@@ -53296,7 +53299,7 @@ var KinesisStreamConsumerProvider = class {
53296
53299
  StreamARN: desc.StreamARN
53297
53300
  };
53298
53301
  } catch (err) {
53299
- this.logger.debug(`DescribeStreamConsumer(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
53302
+ this.logger.debug(`DescribeStreamConsumer(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
53300
53303
  }
53301
53304
  return {
53302
53305
  physicalId,
@@ -53378,7 +53381,7 @@ var KinesisStreamConsumerProvider = class {
53378
53381
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
53379
53382
  } catch (err) {
53380
53383
  if (err instanceof ResourceNotFoundException$10) return void 0;
53381
- this.logger.debug(`ListTagsForResource(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
53384
+ this.logger.debug(`ListTagsForResource(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
53382
53385
  result["Tags"] = [];
53383
53386
  }
53384
53387
  return result;
@@ -53969,7 +53972,7 @@ var EFSProvider = class {
53969
53972
  await this.getClient().send(new DeleteFileSystemCommand({ FileSystemId: fileSystemId }));
53970
53973
  this.logger.debug(`Rolled back partially-created EFS FileSystem ${fileSystemId}`);
53971
53974
  } catch (cleanupError) {
53972
- this.logger.warn(`Failed to roll back partially-created EFS FileSystem ${fileSystemId}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
53975
+ this.logger.warn(`Failed to roll back partially-created EFS FileSystem ${fileSystemId}: ${describeAwsFailure(cleanupError).detail}`);
53973
53976
  }
53974
53977
  if (error instanceof ProvisioningError) throw error;
53975
53978
  const cause = error instanceof Error ? error : void 0;
@@ -54051,7 +54054,7 @@ var EFSProvider = class {
54051
54054
  for (let attempt = 1;; attempt++) try {
54052
54055
  return await op();
54053
54056
  } catch (error) {
54054
- const msg = error instanceof Error ? error.message : String(error);
54057
+ const msg = describeAwsFailure(error).detail;
54055
54058
  const name = error instanceof Error ? error.name : "";
54056
54059
  if (!(/in progress|please retry|incorrect file system life ?cycle state|being (updated|modified)|try again/i.test(msg) || name === "IncorrectFileSystemLifeCycleState" || name === "ConflictException" || name === "ThrottlingException") || attempt >= maxAttempts) throw error;
54057
54060
  this.logger.debug(`Transient error on "${label}" (attempt ${attempt}/${maxAttempts}): ${msg} — retrying in ${delayMs}ms`);
@@ -54793,7 +54796,7 @@ var FSxFileSystemProvider = class {
54793
54796
  await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: fileSystemId }));
54794
54797
  this.logger.warn(`Rolled back partially-created FSx FileSystem ${fileSystemId}`);
54795
54798
  } catch (cleanupError) {
54796
- this.logger.warn(`Failed to roll back partially-created FSx FileSystem ${fileSystemId}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)} — delete it manually to stop billing`);
54799
+ this.logger.warn(`Failed to roll back partially-created FSx FileSystem ${fileSystemId}: ${describeAwsFailure(cleanupError).detail} — delete it manually to stop billing`);
54797
54800
  }
54798
54801
  if (error instanceof ProvisioningError) throw error;
54799
54802
  const cause = error instanceof Error ? error : void 0;
@@ -55014,7 +55017,7 @@ var FSxFileSystemProvider = class {
55014
55017
  if (!updatedFs) try {
55015
55018
  updatedFs = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0];
55016
55019
  } catch (describeError) {
55017
- this.logger.debug(`Post-update attribute refresh for ${physicalId} failed (returning without attributes): ${describeError instanceof Error ? describeError.message : String(describeError)}`);
55020
+ this.logger.debug(`Post-update attribute refresh for ${physicalId} failed (returning without attributes): ${describeAwsFailure(describeError).detail}`);
55018
55021
  }
55019
55022
  this.logger.debug(`Successfully updated FSx FileSystem ${logicalId}`);
55020
55023
  return {
@@ -55260,7 +55263,7 @@ var FSxFileSystemProvider = class {
55260
55263
  return response.FileSystems?.[0];
55261
55264
  } catch (error) {
55262
55265
  const name = error instanceof Error ? error.name : "";
55263
- const msg = error instanceof Error ? error.message : String(error);
55266
+ const msg = describeAwsFailure(error).detail;
55264
55267
  if ((name === "ThrottlingException" || name === "ServiceLimitExceeded" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(msg)) && transientState.count < maxConsecutiveTransient) {
55265
55268
  transientState.count += 1;
55266
55269
  this.logger.debug(`Transient DescribeFileSystems error while polling ${fileSystemId} (${transientState.count}/${maxConsecutiveTransient}): ${msg} — retrying`);
@@ -55919,7 +55922,7 @@ var EMRClusterProvider = class {
55919
55922
  await this.getClient().send(new TerminateJobFlowsCommand({ JobFlowIds: [clusterId] }));
55920
55923
  this.logger.warn(`Rolled back partially-created EMR Cluster ${clusterId}`);
55921
55924
  } catch (cleanupError) {
55922
- this.logger.warn(`Failed to roll back partially-created EMR Cluster ${clusterId}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)} — terminate it manually to stop billing`);
55925
+ this.logger.warn(`Failed to roll back partially-created EMR Cluster ${clusterId}: ${describeAwsFailure(cleanupError).detail} — terminate it manually to stop billing`);
55923
55926
  }
55924
55927
  if (error instanceof ProvisioningError) throw error;
55925
55928
  const cause = error instanceof Error ? error : void 0;
@@ -56097,7 +56100,7 @@ var EMRClusterProvider = class {
56097
56100
  try {
56098
56101
  cluster = (await this.getClient().send(new DescribeClusterCommand({ ClusterId: physicalId }))).Cluster;
56099
56102
  } catch (describeError) {
56100
- this.logger.debug(`Post-update attribute refresh for ${physicalId} failed (returning without attributes): ${describeError instanceof Error ? describeError.message : String(describeError)}`);
56103
+ this.logger.debug(`Post-update attribute refresh for ${physicalId} failed (returning without attributes): ${describeAwsFailure(describeError).detail}`);
56101
56104
  }
56102
56105
  this.logger.debug(`Successfully updated EMR Cluster ${logicalId}`);
56103
56106
  return {
@@ -56190,7 +56193,7 @@ var EMRClusterProvider = class {
56190
56193
  return response.Cluster;
56191
56194
  } catch (error) {
56192
56195
  const name = error instanceof Error ? error.name : "";
56193
- const msg = error instanceof Error ? error.message : String(error);
56196
+ const msg = describeAwsFailure(error).detail;
56194
56197
  if ((name === "ThrottlingException" || name === "InternalServerException" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|throttl|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(msg)) && transientState.count < maxConsecutiveTransient) {
56195
56198
  transientState.count += 1;
56196
56199
  this.logger.debug(`Transient DescribeCluster error while polling ${clusterId} (${transientState.count}/${maxConsecutiveTransient}): ${msg} — retrying`);
@@ -56737,7 +56740,7 @@ var EMRInstanceGroupConfigProvider = class {
56737
56740
  const clientRegion = await this.getClient().config.region();
56738
56741
  assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, physicalId);
56739
56742
  this.logger.debug(`EMR instance group ${physicalId} scale-to-0 skipped (cluster/group gone): ${error.message}`);
56740
- } else this.logger.warn(`Best-effort scale-to-0 of EMR instance group ${physicalId} failed: ${error instanceof Error ? error.message : String(error)} — its instances are released when the parent cluster terminates`);
56743
+ } else this.logger.warn(`Best-effort scale-to-0 of EMR instance group ${physicalId} failed: ${describeAwsFailure(error).detail} — its instances are released when the parent cluster terminates`);
56741
56744
  }
56742
56745
  return;
56743
56746
  }
@@ -56824,7 +56827,7 @@ var EMRInstanceGroupConfigProvider = class {
56824
56827
  return;
56825
56828
  } catch (error) {
56826
56829
  const name = error instanceof Error ? error.name : "";
56827
- const msg = error instanceof Error ? error.message : String(error);
56830
+ const msg = describeAwsFailure(error).detail;
56828
56831
  if ((name === "ThrottlingException" || name === "InternalServerException" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|throttl|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(msg)) && transientState.count < maxConsecutiveTransient) {
56829
56832
  transientState.count += 1;
56830
56833
  this.logger.debug(`Transient ListInstanceGroups error while polling ${groupId} (${transientState.count}/${maxConsecutiveTransient}): ${msg} — retrying`);
@@ -57051,7 +57054,7 @@ var EMRInstanceFleetConfigProvider = class {
57051
57054
  const clientRegion = await this.getClient().config.region();
57052
57055
  assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, physicalId);
57053
57056
  this.logger.debug(`EMR instance fleet ${physicalId} scale-to-0 skipped (cluster/fleet gone): ${error.message}`);
57054
- } else this.logger.warn(`Best-effort scale-to-0 of EMR instance fleet ${physicalId} failed: ${error instanceof Error ? error.message : String(error)} — its instances are released when the parent cluster terminates`);
57057
+ } else this.logger.warn(`Best-effort scale-to-0 of EMR instance fleet ${physicalId} failed: ${describeAwsFailure(error).detail} — its instances are released when the parent cluster terminates`);
57055
57058
  }
57056
57059
  return;
57057
57060
  }
@@ -57178,7 +57181,7 @@ var EMRInstanceFleetConfigProvider = class {
57178
57181
  return;
57179
57182
  } catch (error) {
57180
57183
  const name = error instanceof Error ? error.name : "";
57181
- const msg = error instanceof Error ? error.message : String(error);
57184
+ const msg = describeAwsFailure(error).detail;
57182
57185
  if ((name === "ThrottlingException" || name === "InternalServerException" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|throttl|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(msg)) && transientState.count < maxConsecutiveTransient) {
57183
57186
  transientState.count += 1;
57184
57187
  this.logger.debug(`Transient ListInstanceFleets error while polling ${fleetId} (${transientState.count}/${maxConsecutiveTransient}): ${msg} — retrying`);
@@ -58232,7 +58235,7 @@ var FirehoseProvider = class {
58232
58235
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
58233
58236
  } catch (err) {
58234
58237
  if (err instanceof ResourceNotFoundException$12) return void 0;
58235
- this.logger.debug(`Firehose ListTagsForDeliveryStream(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
58238
+ this.logger.debug(`Firehose ListTagsForDeliveryStream(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
58236
58239
  result["Tags"] = [];
58237
58240
  }
58238
58241
  return result;
@@ -58696,7 +58699,7 @@ var CloudTrailProvider = class {
58696
58699
  newEventSelectors = requireConfigArray(rawEventSelectors, "AWS::CloudTrail::Trail EventSelectors");
58697
58700
  } catch (error) {
58698
58701
  eventSelectorsUnusable = true;
58699
- this.logger.warn(`${error instanceof Error ? error.message : String(error)} The trail's existing event selectors are left untouched for this update rather than reset to the AWS default.`);
58702
+ this.logger.warn(`${describeAwsFailure(error).detail} The trail's existing event selectors are left untouched for this update rather than reset to the AWS default.`);
58700
58703
  }
58701
58704
  const oldEventSelectors = previousProperties["EventSelectors"];
58702
58705
  if (!eventSelectorsUnusable && JSON.stringify(newEventSelectors) !== JSON.stringify(oldEventSelectors)) {
@@ -58709,7 +58712,7 @@ var CloudTrailProvider = class {
58709
58712
  EventSelectors: [...eventSelectorsToSend]
58710
58713
  }));
58711
58714
  } catch (error) {
58712
- const message = error instanceof Error ? error.message : String(error);
58715
+ const message = describeAwsFailure(error).detail;
58713
58716
  if (!isRemoval || !/advanced[\s-]*event[\s-]*selector/i.test(message)) throw error;
58714
58717
  this.logger.warn(`CloudTrail Trail ${logicalId}: skipping the EventSelectors reset — the trail is using AdvancedEventSelectors, which AWS manages through a separate API, so there are no basic event selectors to clear (${message})`);
58715
58718
  }
@@ -58878,7 +58881,7 @@ var CloudTrailProvider = class {
58878
58881
  const tagsResp = await this.getClient().send(new ListTagsCommand$2({ ResourceIdList: [trail.TrailARN] }));
58879
58882
  tags = normalizeAwsTagsToCfn(tagsResp.ResourceTagList?.[0]?.TagsList);
58880
58883
  } catch (err) {
58881
- this.logger.debug(`CloudTrail ListTags(${trail.TrailARN}) failed: ${err instanceof Error ? err.message : String(err)}`);
58884
+ this.logger.debug(`CloudTrail ListTags(${trail.TrailARN}) failed: ${describeAwsFailure(err).detail}`);
58882
58885
  }
58883
58886
  result["Tags"] = tags;
58884
58887
  return result;
@@ -59886,7 +59889,7 @@ var CodeCommitRepositoryProvider = class {
59886
59889
  try {
59887
59890
  await this.getClient().send(new DeleteRepositoryCommand$1({ repositoryName }));
59888
59891
  } catch (cleanupError) {
59889
- this.logger.warn(`Failed to clean up CodeCommit Repository ${repositoryName} after a post-create failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
59892
+ this.logger.warn(`Failed to clean up CodeCommit Repository ${repositoryName} after a post-create failure: ${describeAwsFailure(cleanupError).detail}`);
59890
59893
  }
59891
59894
  }
59892
59895
  /**
@@ -60067,7 +60070,7 @@ var DLMLifecyclePolicyProvider = class {
60067
60070
  try {
60068
60071
  arn = await this.fetchPolicyArn(response.PolicyId);
60069
60072
  } catch (err) {
60070
- this.logger.warn(`Created DLM Lifecycle Policy ${response.PolicyId} but could not fetch its ARN: ${err instanceof Error ? err.message : String(err)}`);
60073
+ this.logger.warn(`Created DLM Lifecycle Policy ${response.PolicyId} but could not fetch its ARN: ${describeAwsFailure(err).detail}`);
60071
60074
  }
60072
60075
  this.logger.debug(`Successfully created DLM Lifecycle Policy ${logicalId}: ${response.PolicyId}`);
60073
60076
  return {
@@ -60436,7 +60439,7 @@ var S3VectorsProvider = class {
60436
60439
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$17({ resourceArn: bucket.vectorBucketArn }));
60437
60440
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.tags);
60438
60441
  } catch (err) {
60439
- this.logger.debug(`S3Vectors ListTagsForResource(${bucket.vectorBucketArn}) failed: ${err instanceof Error ? err.message : String(err)}`);
60442
+ this.logger.debug(`S3Vectors ListTagsForResource(${bucket.vectorBucketArn}) failed: ${describeAwsFailure(err).detail}`);
60440
60443
  result["Tags"] = [];
60441
60444
  }
60442
60445
  else this.logger.debug(`S3Vectors GetVectorBucket(${physicalId}) returned no vectorBucketArn; skipping Tags readback`);
@@ -60531,7 +60534,7 @@ var S3DirectoryBucketProvider = class {
60531
60534
  return azId;
60532
60535
  }
60533
60536
  } catch (error) {
60534
- this.logger.debug(`Failed to resolve AZ ID for ${azName}: ${error instanceof Error ? error.message : String(error)}`);
60537
+ this.logger.debug(`Failed to resolve AZ ID for ${azName}: ${describeAwsFailure(error).detail}`);
60535
60538
  }
60536
60539
  return azName;
60537
60540
  }
@@ -60717,7 +60720,7 @@ var S3DirectoryBucketProvider = class {
60717
60720
  this.logger.debug(`Successfully deleted S3 Express Directory Bucket ${logicalId}`);
60718
60721
  return;
60719
60722
  } catch (error) {
60720
- const msg = error instanceof Error ? error.message : String(error);
60723
+ const msg = describeAwsFailure(error).detail;
60721
60724
  if (msg.includes("not empty") || msg.includes("BucketNotEmpty")) {
60722
60725
  if (!allowAutoEmpty) throw new Error(`bucket ${bucketName} is not empty. Matching CloudFormation, cdkd does not delete a non-empty directory bucket without an explicit opt-in. Delete all objects first (e.g. aws s3 rm s3://${bucketName} --recursive) and destroy again.`);
60723
60726
  this.logger.info(`Directory bucket ${bucketName} not empty (attempt ${attempt}/${maxAttempts}), emptying (auto-delete opt-in present)...`);
@@ -61257,7 +61260,7 @@ var S3TablesProvider = class {
61257
61260
  try {
61258
61261
  resolved = await this.resolveTableParts(physicalId);
61259
61262
  } catch (err) {
61260
- this.logger.warn(`S3 Tables Table ${physicalId}: could not resolve its identity for drift (${err instanceof Error ? err.message : String(err)}); reporting drift as unknown.`);
61263
+ this.logger.warn(`S3 Tables Table ${physicalId}: could not resolve its identity for drift (${describeAwsFailure(err).detail}); reporting drift as unknown.`);
61261
61264
  return;
61262
61265
  }
61263
61266
  if (resolved === "not-found" || resolved === "unparseable") return void 0;
@@ -61596,7 +61599,7 @@ var S3TablesProvider = class {
61596
61599
  });
61597
61600
  return out;
61598
61601
  } catch (err) {
61599
- this.logger.debug(`readTagsBestEffort: ListTagsForResource failed for ${resourceArn}: ${err instanceof Error ? err.message : String(err)} — emitting Tags: []`);
61602
+ this.logger.debug(`readTagsBestEffort: ListTagsForResource failed for ${resourceArn}: ${describeAwsFailure(err).detail} — emitting Tags: []`);
61600
61603
  return [];
61601
61604
  }
61602
61605
  }
@@ -63513,7 +63516,7 @@ var ACMCertificateProvider = class {
63513
63516
  idempotencyToken.release();
63514
63517
  return;
63515
63518
  }
63516
- const detail = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
63519
+ const detail = describeAwsFailure(cleanupError).detail;
63517
63520
  this.logger.warn(`Could not delete the ACM certificate ${certificateArn} that the failed create of ${logicalId} requested: ${detail}`);
63518
63521
  return `The certificate ${certificateArn} this attempt created could NOT be deleted, and cdkd is not tracking it -- retire it with \`aws acm delete-certificate --certificate-arn ${certificateArn} --region ${this.regionOfArn(certificateArn)}\` (the reason is in the warning above).`;
63519
63522
  }
@@ -63540,8 +63543,8 @@ var ACMCertificateProvider = class {
63540
63543
  }
63541
63544
  } catch (error) {
63542
63545
  const inUse = isCertificateInUseError(error);
63543
- orphanReason = inUse ? `old certificate ${physicalId} is still in use by another resource and was not deleted` : `old certificate ${physicalId} could not be deleted: ${String(error)}`;
63544
- this.logger.warn(`Failed to delete old ACM certificate ${physicalId} during replacement: ${String(error)}. ` + (inUse ? "This usually means a consumer (e.g. a CloudFront distribution) still references it; it can be deleted once DescribeCertificate.InUseBy is empty. " : "") + `The old certificate may be orphaned and require manual cleanup.`);
63546
+ orphanReason = inUse ? `old certificate ${physicalId} is still in use by another resource and was not deleted` : `old certificate ${physicalId} could not be deleted: ${safeStringify(error)}`;
63547
+ this.logger.warn(`Failed to delete old ACM certificate ${physicalId} during replacement: ${safeStringify(error)}. ` + (inUse ? "This usually means a consumer (e.g. a CloudFront distribution) still references it; it can be deleted once DescribeCertificate.InUseBy is empty. " : "") + `The old certificate may be orphaned and require manual cleanup.`);
63545
63548
  }
63546
63549
  const base = {
63547
63550
  physicalId: createResult.physicalId,
@@ -94392,4 +94395,4 @@ function buildProgram() {
94392
94395
 
94393
94396
  //#endregion
94394
94397
  export { buildProgram };
94395
- //# sourceMappingURL=program-BKuJRiz3.js.map
94398
+ //# sourceMappingURL=program-DaoJ7P4H.js.map