What's Changed
New Contributors
- @adamkeener made their first contribution in #1683
- @po-luka-miletic made their first contribution in #1687
[1.5.11] — 2026-09-13
Added
- CloudFormation —
ValidateTemplatereports capabilities and transforms — it answeredDescriptionandParametersonly, so a caller checking a template before a deploy could not see that it needsCAPABILITY_IAMor that it declares a transform. It now returnsCapabilities,CapabilitiesReasonandDeclaredTransforms, on the ruleGetTemplateSummaryalready used. Contributed by @iot-rocket. - CloudFormation — a stack and a change set report their capabilities —
DescribeStacksandDescribeChangeSetleft theCapabilitiesmember out, so a client could not see what a deploy had acknowledged. A stack reports what its lastCreateStackorUpdateStackacknowledged, a change set what it was created with, and executing one hands its set to the stack. Contributed by @iot-rocket.
Changed
- Lambda — warm local custom runtimes —
provided.*bootstraps reuse the subprocess worker pool instead of restarting on every invocation. Each invocation gets its request metadata through the Lambda Runtime API, concurrent calls lease separate workers, and a failed environment is discarded before reuse. Durableprovided.*invocations keep the one-shot executor, since a bootstrap reads its environment once, at spawn. Contributed by @jayjanssen.
Fixed
- S3 — the
s3:TestEventno longer reaches Lambda targets —PutBucketNotificationConfigurationfanned the test event out to every destination, but AWS sends it to SQS and SNS only and verifies a Lambda destination through its function permissions. The payload has noRecordsarray, so every S3-triggered function raised on it, and the async path then retried it toMaximumRetryAttemptsand dropped it in the function's DLQ, where an event AWS never sends looked like a lost message. Queue and topic destinations still receive it. Contributed by @ppettitau. - S3 — a presigned upload is no longer rejected for the checksum in its query string — current SDKs sign
x-amz-checksum-crc32into every presignedPutObject, computed over the empty body, because whoever holds the URL picks the body later. MiniStack hoisted that parameter into the request headers and verified it against the real body, so a stockgetSignedUrlupload failed with400 BadDigest. The checksum value parameters are no longer hoisted: they still take part in signature verification, so rewriting one is still403, and a checksum sent as a real header is verified as before. Contributed by @bognari. - S3 — a presigned URL is verified against the credentials that signed it — the signature was recomputed with the server's own secret, so a URL signed with an IAM user's or an STS session's key verified against the wrong one, and a deactivated key, an expired session or a session token that was never issued were all accepted. The signing key is resolved to its owner and the URL verified with that key's secret, with the exact session token required for temporary credentials:
InvalidAccessKeyId(403) for an unknown or inactive key,ExpiredTokenorInvalidToken(400) for a bad token. UnderAUTH=truean HTTP request also resolves its key to the owning account andGetSessionTokenrefuses temporary credentials. Contributed by @Areson. - Lambda — an SDK call from a function runs under its execution role — under
AUTH=trueevery runtime received account-root credentials, so a call from a handler bypassed the role the function declares and a policy that should have denied it did nothing. Each invocation now gets temporary credentials for itsRoleon the warm workers, the Docker and provided runtimes and the one-shot executor, and the IAM layer resolves the assumed role's account, a table's index ARNs and projection keys, and an EventBridgePutEventsbus. Contributed by @adamkeener. - Lambda — a Node custom resource signals its stack in the docker executor — the response submitters the CDK bundles into its custom-resource handlers build the
ResponseURLPUT from the URL's hostname and path only and hand it tohttps.request, so underLAMBDA_EXECUTOR=dockerthe callback went out over TLS to port 443, nothing answered, and the resource hung its stack untilServiceTimeout. The shim the executor injects now turns https to the gateway hosts, on the https default port or the gateway port, into plain http on the gateway port; any other host or port keeps TLS. Contributed by @iot-rocket. - Lambda — a durable invocation runs on the warm pool — durable Python and Node.js invocations went to the one-shot executor, because the three
AWS_LAMBDA_DURABLE_*variables change per call while a pooled worker's environment is fixed at spawn. Each paid a fresh interpreter start inside the function'sTimeout, whose default is 3 seconds, so on a loaded machine every durable invocation timed out. The values travel beside the payload now, and both bootstraps apply them before the handler runs and drop them when the next invocation is not durable. Contributed by @iot-rocket. - Lambda — two durable executions of one function no longer share a callback — the
CallbackIdwas the operation id, which the durable SDK derives from the workflow position, so two concurrent executions registered the same id: the second overwrote the first, an answer sent for one completed the other, and the abandoned execution's own callback then answeredCallbackTimeoutException. The id is unique per execution and stable across replays and restarts. Reported by @Nhollas. - ECS —
RunTaskreturns before the image is pulled — the call blocked while Docker pulled the image and started the container. A task is registered and returned immediately, and walksPENDING→ACTIVATING(the pull, withpullStartedAtstamped) →RUNNING→STOPPED, with a failed start reported asTaskFailedToStart.StopTaskand a reset no longer race the starter, andpendingCountandrunningCountkeep countingPENDINGandRUNNINGonly. Contributed by @po-luka-miletic. - Transcribe —
StartTranscriptionJobreturns a job alreadyIN_PROGRESS— the start response reportedQUEUEDwith noStartTimeand the job reachedIN_PROGRESSonly from the background worker, so a caller that reads the status off the response and then waits for the terminal event never saw an in-progress state. Jobs startIN_PROGRESSwithStartTimeset, andTRANSCRIBE_JOB_RUN_SECONDScovers the whole run.QUEUED, which AWS reaches only throughJobExecutionSettings.AllowDeferredExecutionat the concurrent job limit, is not modelled. Contributed by @ppettitau. - Cognito —
SetIdentityPoolRoleskeeps the role mappings it is given — the call storedRolesonly andGetIdentityPoolRolesanswered a hard-codedRoleMappings: {}, so a mapping set through the API or declared on a CloudFormation attachment was accepted and dropped. Both members are stored on the pool and served back; the call sets the whole configuration, so an omittedRoleMappingsclears what was there. The map is stored as sent and takes no part in credential vending. Contributed by @iot-rocket. - API Gateway v2 —
UpdateApikeeps the description and the API key selection expression — the call applied five members and discardedDescriptionandApiKeySelectionExpression, so an update lost what the create had stored. Both are applied now, and aCorsConfigurationon the call replaces the stored one; removing one isDeleteCorsConfiguration, whichDELETE /v2/apis/{apiId}/corsserves. Contributed by @iot-rocket. - EC2 — a security group's IPv6 and prefix-list rules survive the read —
DescribeSecurityGroupsrenderedipv6RangesandprefixListIdsas empty elements and dropped every range description, so a rule authorized with an IPv6 CIDR or a prefix list was invisible on the next read and Terraform planned the same egress change on every run. All three families are reported, each with its description. Reported by @edersonbrilhante. - EC2 — a launch template keeps its metadata options and shutdown behaviour —
CreateLaunchTemplateparsed neitherMetadataOptionsnorInstanceInitiatedShutdownBehavior, so both were discarded at creation and every refresh reported them as newly added. The IMDS settings and the shutdown behaviour are stored and reported on the version, with the response-onlyStatethe API carries. Reported by @edersonbrilhante. - SSM — a
SecureStringparameter reports itsKeyId— the key was stored and never served:DescribeParametersandGetParameterHistoryleft the member out, so a caller read an empty key and updated the parameter on every run. Both report it forSecureStringparameters, the only ones it applies to, and an emptyKeyIdon the request means the account default.GetParameteris unchanged, since its response shape has no such member. Reported by @edersonbrilhante. - CloudWatch Logs — a log group reports its class and its KMS key —
DescribeLogGroupsomittedlogGroupClassandkmsKeyIdandCreateLogGroupdiscarded both, so a consumer reading the class back saw an empty value and planned a replacement of a group that had not changed. Both are stored and reported, with the API's default ofSTANDARDand an unknown class refused, andAWS::Logs::LogGroupcarriesLogGroupClassandKmsKeyIdthrough the stack. Reported by @edersonbrilhante. - CloudFormation —
UpdateReplacePolicy: Retainholds for every handler-side replacement — 24 update handlers that replace a resource themselves deleted the predecessor inline, so a template that retains it lost the resource while the stack still recordedDELETE_SKIPPED; only the handlers on the shared rename helper honoured the policy. Every inline delete goes through one helper that reads the policy the engine publishes, and the three handlers that deleted before creating create first. Contributed by @iot-rocket. - CloudFormation — a resource inside a nested stack reads its own
UpdateReplacePolicy— the nested-stack deploy loop never published the policy, so a child resource's handler saw whatever the parent's loop had left behind: a retained parent kept every child's predecessor, an unretained one deleted a retained child's. Each child resource's policy is now resolved the way the engine resolves it, intrinsics included, and published around that resource's update only. Contributed by @iot-rocket. - CloudFormation — a nested stack's IAM resources need the parent's capabilities — the check under
AUTH=trueread the parent template only, so a parent deployed without--capabilitiesprovisioned a child full of IAM roles throughAWS::CloudFormation::Stack. The child template is checked against the set the parent acknowledged, and a child's child reads the same set; a missing one fails the nested-stack resource withRequires capabilities : [CAPABILITY_IAM]and the parent rolls back. WithoutAUTHnothing changes. Contributed by @iot-rocket. - CloudFormation — an unknown
Capabilitiesvalue is refused —CreateStack,UpdateStackandCreateChangeSetaccepted any string, so a typo or another tool's capability was kept without effect and the deploy behaved as if it had been acknowledged. The member is checked against the three documented values, joined with the other request-level problems into one message. Contributed by @iot-rocket. - CloudFormation — the SAM transform reads the transforms the response reports —
ValidateTemplatenormalises theTransformsection in every form it takes, while the deploy path had its own normalisation that left the macro object (Transform: {Name: AWS::Serverless-2016-10-31}) unmatched, so such a template was reported as declaring the SAM transform and then deployed untransformed, failing onAWS::Serverless::Function. Both read one function now. Contributed by @iot-rocket. - CloudFormation — an
AWS::ApiGateway::Method'sMethodResponsesandIntegrationResponsesare provisioned — the provisioner read the method and integration properties and discarded both response lists, so a REST API deployed from a template lost its mapped response headers. The visible casualty was the CDK'sdefaultCorsPreflightOptions, whose generatedOPTIONSmethod returns theAccess-Control-Allow-*headers through a MOCK integration: the preflight answered without a single CORS header and the browser blocked the request. Both lists are provisioned onto the method now, and a stack update reprovisions them. Contributed by @ppettitau. - CloudFormation —
Fn::GetAtton a user pool client'sClientSecretresolves — the provisioner returnedClientIdalone, so a template readingClientSecretorNamefailed withRequested attribute ClientSecret does not exist in schemaand rolled the stack back, on the create and on the update that follows it. All three attributes the type declares are returned, on both paths; a client created withoutGenerateSecretreads empty. Reported by @JoshuaSmeda. - CloudFormation —
AWS::Cognito::IdentityPoolRoleAttachmentupdates in place — the type had no update handler, so a stack update fell through to the create.RolesandRoleMappingsare re-applied to the pool the attachment sits on and a dropped property reverts to its create default, sinceSetIdentityPoolRolestakes the whole configuration; a changedIdentityPoolIdreplaces, configuring the new pool before clearing the old. Contributed by @iot-rocket. - CloudFormation —
AWS::Cognito::UserPoolResourceServerupdates in place, and a move between pools is refused — the physical id is theIdentifieralone while the record is keyed by pool and identifier, so a template that repointedUserPoolIdleft two live resource servers vending the same scopes.NameandScopesgo throughUpdateResourceServeron the existing server, a changedIdentifierreplaces, and a changedUserPoolIdgets CloudFormation's refusal to replace a custom-named resource. Contributed by @iot-rocket. - CloudFormation —
AWS::SQS::QueuePolicyandAWS::SNS::TopicPolicyupdate in place — neither had an update handler, so a changed policy fell through to create under a fresh physical id; the engine recorded a replacement and the cleanup delete then stripped the policy the create had just written, leaving the queue or topic with none. Both properties are No interruption, so the resource keeps its id, writes the document on every queue or topic the template names and removes it from one the template dropped. Contributed by @iot-rocket. - CloudFormation —
AWS::SNS::Subscriptionupdates in place — a changedFilterPolicyorRawMessageDeliveryre-subscribed under a freshSubscriptionArn, soRefmoved on every update. The No-interruption attributes go throughSetSubscriptionAttributeson the existing subscription and a dropped one reverts to the create default, whileTopicArn,ProtocolandEndpointreplace. The create also storesDeliveryPolicy,RedrivePolicyandSubscriptionRoleArn, which it dropped. Contributed by @iot-rocket. - CloudFormation —
AWS::Lambda::Aliasupdates in place, andProvisionedConcurrencyConfigreaches the service — the create ignoredProvisionedConcurrencyConfigand storedRoutingConfigin the template's list shape, on which boto3'sGetAliasfails. The No-interruption properties go throughUpdateAliasand the provisioned-concurrency put and delete on the existing alias,NameorFunctionNamereplaces, and the routing weights are stored as the{version: weight}mapGetAliasreturns. Contributed by @iot-rocket. - CloudFormation —
AWS::Logs::SubscriptionFilterupdates in place, and a group change moves it — a changedLogGroupNamefell through to create, which wrote the filter on the new group under its unchanged name, so the engine saw no replacement and the old group kept its copy. The No-interruption properties go throughPutSubscriptionFilteron the existing filter, and a changedFilterNameorLogGroupNamecreates the new filter before removing the old. Contributed by @iot-rocket. - CloudFormation —
AWS::IAM::InstanceProfileupdates in place, and a named profile refuses aPathchange — aRoleschange fell through to create, which rebuilt the record without its tags and stored whole role records, on whichGetInstanceProfileanswered 500.Rolesis applied to the existing record, which keeps its ARN, id and tags;InstanceProfileNameandPathreplace, so a custom-named profile whosePathchanges fails the update as CloudFormation fails it. Contributed by @iot-rocket. - CloudFormation — the four HTTP API types update in place —
AWS::ApiGatewayV2::Api,Integration,RouteandStagehad create handlers only, so a stack update minted a new id for each: the API re-created every child under a newApiIdandApiEndpoint(and rolled the stack back when the id was pinned withms-custom-id), an integration or route left its predecessor on the API whileRefmoved, and a stage lost itsCreatedDateand its tags. Each now updates through the service's own call and keeps its id, a dropped property reverts to the create's default, and onlyProtocolType,ApiIdorStageNamereplaces. Contributed by @iot-rocket. - CloudFormation —
AWS::CloudFront::Distributionupdates in place, and a provisioned distribution is readable — a stack update minted a newIdandDomainNameand the engine deleted the old distribution, though both of the type's properties are No interruption; and the create stored an empty configuration, soGetDistributionandGetDistributionConfiganswered 500 on every CloudFormation distribution. The create renders the template'sDistributionConfiginto the API's shape, and the update keepsId,ARN,DomainNameand the invalidation history, rolls theETagand reconciles tags, asUpdateDistributiondoes. Contributed by @iot-rocket. - CloudFormation — the five CloudFront policy, OAC and function types update in place —
CachePolicy,OriginRequestPolicy,ResponseHeadersPolicy,OriginAccessControlandFunctionhad create handlers only, so an update fell through to a create that found the record it had made before and returned it untouched: the stack reportedUPDATE_COMPLETEwhile the service kept serving the old configuration. Each updates its record now, keeping the id a distributionRefs, and a rename onto a taken name is refused. Contributed by @iot-rocket.