# Changelog All notable changes to MiniStack will be documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Versioning follows [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Fixed - **ECS — `ListServiceDeployments` and `DescribeServiceDeployments`** — both answered an empty list for every service, so the AWS provider's wait on a new `aws_ecs_service` never finished once it took the service-deployment path (it does when the deployment's `createdAt` is after the time the client noted before `CreateService`). Each deployment of a service is now listed, newest first, with AWS's ARNs, `createdAt` and `status` filters and `status` moving from `IN_PROGRESS` to `SUCCESSFUL`, and described with its source and target revisions. Contributed by @kharabasz. - **Route 53 — metric and calculated health checks no longer get `RequestInterval` and `FailureThreshold`** — `CreateHealthCheck` added `RequestInterval` 30 and `FailureThreshold` 3 to `CLOUDWATCH_METRIC` and `CALCULATED` checks, so Terraform replaced them on every plan. Only endpoint checks get them now, as on AWS, and a metric check without `InsufficientDataHealthStatus` gets `LastKnownStatus`. `CreateHealthCheck` and `UpdateHealthCheck` also reject what AWS rejects for metric, calculated and recovery-control checks, with AWS's `InvalidInput` messages and order: a metric check now needs an existing metric alarm in its `AlarmIdentifier` region (not a percentile, metric-math or high-resolution alarm), fields the type cannot carry are refused, a calculated check needs a `HealthThreshold` and existing child checks, and a recovery-control check cannot be updated. An `UpdateHealthCheck` with no members succeeds, a body that is not XML answers `MalformedInput`, and child health check IDs are no longer stored empty. MiniStack does not check that a routing control exists. Fixes #2603. Contributed by @kharabasz. ### Added - **SES — sending events through EventBridge** — configuration set event destinations were stored but never fired. Each send now publishes `aws.ses` events to the set's EventBridge destination, with the outcomes AWS gives the mailbox simulator. Adds `PutEmailIdentityConfigurationSetAttributes`; EventBridge now delivers to CloudWatch Logs log group targets. ## [1.5.39] — 2026-11-08 ### Added - **Secrets Manager — `RemoveRegionsFromReplication` and `StopReplicationToReplica`** — both answered `Unknown action`, so `terraform destroy` of a secret with a `replica` block failed. The first deletes the listed regions' replicas and returns the remaining `ReplicationStatus`; the second, called in a replica's region, makes it a standalone secret. Contributed by @kharabasz. - **Cognito — attribute verification** — adds `GetUserAttributeVerificationCode` and `VerifyUserAttribute`. A changed email or phone number now becomes unverified and gets a code where the pool auto-verifies it, and `AttributesRequireVerificationBeforeUpdate` keeps the old value until the new one is verified. Contributed by @toby6578. - **Cognito — hosted UI forgot password and MFA** — the hosted sign-in pages now have a forgot-password flow, ask for a TOTP or SMS code after the password, and enrol TOTP where the pool requires MFA. Messages match AWS's classic hosted UI; the pages render straight from `POST /login`, and reset codes are checked only with `AUTH=true`. Contributed by @toby6578. - **Cognito — RFC 8707 resource indicators on managed login** — on a `ManagedLoginVersion` 2 domain, a `resource` naming one of the pool's resource servers now becomes the access token's `aud`, and refreshes keep it. An unregistered one fails the code exchange with `invalid_grant`. Contributed by @toby6578. - **Cognito — the `PostAuthentication` trigger** — `LambdaConfig.PostAuthentication` was stored and never invoked. It now runs after a password, MFA or challenge sign-in through the API, before tokens are issued and before `NEW_PASSWORD_REQUIRED`, but not on refresh. A failing Lambda fails the sign-in with `UserLambdaValidationException`, `InvalidLambdaResponseException` or `UnexpectedLambdaException`. Reported by @ryuzo-hayashi. - **CloudFront — `cf.kvs()` in CloudFront Functions** — `import cf from 'cloudfront'` failed in `cloudfront-js-2.0`. `get()` (string, json or bytes), `exists()` and `meta()` now read the function's associated KeyValueStore; a missing key throws `KeyNotFound`, and `cf.kvs()` in a function without a store throws `InternalError`. Reported by @mkusaka. - **KMS — the `aws/s3` AWS managed key** — an S3 write with `aws:kms` and no key ID (or `alias/aws/s3`) was refused. S3 now creates the account's `aws/s3` key on first use (KeyManager `AWS`, AWS's description and key policy, alias `alias/aws/s3`) and encrypts with it, as does a bucket default of `aws:kms` without `KMSMasterKeyID`. Contributed by @kharabasz. - **S3 — PutObject through another account's access point** — it was refused. It now succeeds when the caller's identity policy, the access point policy and the owner's bucket policy all allow it, and lands in the owner's bucket under its default encryption; a missing grant answers AWS's AccessDenied for that step. Contributed by @kharabasz. ### Changed - **Secrets Manager — a request body that is not one JSON object** — an empty or blank body was read as `{}`, and `[]`, `null` or a bare string crashed with a 500. Every action now answers `SerializationException` for a body that is not a single JSON object (a list names itself, the rest carry no message); whitespace around the object is fine. Contributed by @kharabasz. - **Secrets Manager — `DeleteSecret` on a primary that still has replicas** — it deleted the replicas with the primary. It now answers `InvalidParameterException` ("You can't delete secret … that still has replica regions [...]"), so replicas are removed first; called in a replica's region it answers "Operation not permitted on a replica secret". Contributed by @kharabasz. ### Fixed - **RDS — Aurora member reboots no longer stick** — after `ModifyDBCluster` rotated the master password, a rebooted member stayed `rebooting` or went `failed`; its readiness check now uses the cluster's password. Deleting an instance no longer recomputes every cluster's status, which left a cluster with a member mid-reboot in `creating`. Contributed by @jayjanssen. - **Auto Scaling — `InstanceRequirements` launch templates and overrides are checked** — a plain `LaunchTemplate` with `InstanceRequirements` now answers `InvalidQueryParameter`, and bad overrides (neither or both of `InstanceType` and `InstanceRequirements`, mixed kinds, partial weights, duplicates, more than 40) answer `ValidationError` with AWS's messages. Contributed by @kharabasz. - **S3 — SSE-KMS keys are resolved through KMS** — a write stored the key reference as given and accepted keys that do not exist. It now stores and echoes the key ARN and refuses an unknown key with `KMS.NotFoundException` before any authorization, as on AWS; a write naming a key MiniStack's KMS does not hold now fails, so create the key first. Contributed by @kharabasz. - **S3 — bucket policies on `s3:x-amz-server-side-encryption-aws-kms-key-id`** — with `AUTH=true` the key was never set, so a policy denying uploads under any other KMS key also denied the right one. Writes now carry the key ARN however the key is named, or the bucket default's, and multipart parts carry their upload's key. Contributed by @kharabasz. - **Auto Scaling — `DesiredCapacityType` is reported as AWS reports it** — since 1.5.38 every group reported `units`, so Terraform planned a change on every run. Only a group with a `MixedInstancesPolicy` now has one, `vcpu` and `memory-mib` need `InstanceRequirements`, and state saved by 1.5.38 is cleaned on restore. Contributed by @kharabasz. - **CloudFront — `Compress: true` compresses responses** — origin responses passed through uncompressed. They are now gzipped, or Brotli-encoded when the optional `brotli` package is installed, under AWS's conditions (status, size, `Content-Type`, no `Content-Encoding`); a strong `ETag` becomes weak, and the origin gets the normalized `Accept-Encoding` (`br,gzip`, `gzip`, `br` or `identity`). Reported by @skialpine. - **Cognito — MFA through the API** — a user whose pool requires MFA and who has no factor signed in without one. They now get `MFA_SETUP` and, once enrolled, a `SOFTWARE_TOKEN_MFA` challenge; a TOTP enrolled on the hosted pages is challenged by the API too, and five wrong codes lock the user out for a growing time, at most 15 minutes. - **IAM — request condition keys with `AUTH=true`** — keys such as `s3:signatureversion`, `s3:x-amz-storage-class`, `kms:EncryptionContext:*`, `secretsmanager:VersionStage`, `ssm:Overwrite`, `sns:Protocol`, `ec2:Region` and `iam:PermissionsBoundary` were never set, so a policy conditioned on them denied valid requests. They are now set from the request. - **S3 — `ListMultiRegionAccessPoints` pages** — the token was a position, so a create or delete between pages skipped or repeated an access point; it now names the last one returned. ## [1.5.38] — 2026-11-05 ### Added - **RDS — IAM database authentication for PostgreSQL and Aurora PostgreSQL** — a role granted `rds_iam` could not log in with a token from `generate_db_auth_token`. With IAM database authentication enabled it now logs in with one, checked as for MySQL (with `AUTH=true` also the token and `rds-db:connect`); other users keep password authentication. Reported by @kharabasz. - **Cognito — refresh token rotation** — a client with `RefreshTokenRotation` `ENABLED` now gets a new refresh token from `GetTokensFromRefreshToken` and `/oauth2/token`. Reusing a replaced token outside `RetryGracePeriodSeconds` answers `RefreshTokenReuseException`, and `REFRESH_TOKEN_AUTH` answers `UnsupportedOperationException` for such a client. Contributed by @toby6578. - **Cognito — the `CustomEmailSender` trigger** — `LambdaConfig.CustomEmailSender` was stored and never invoked. It now receives invitation, sign-up, resend, forgot-password and email OTP messages with AWS's event, the code encrypted as an AWS Encryption SDK message under the pool's `KMSKeyID`, so it decrypts through MiniStack's KMS. Contributed by @toby6578. - **Cognito — managed login branding** — `CreateManagedLoginBranding`, `DescribeManagedLoginBranding`, `DescribeManagedLoginBrandingByClient`, `UpdateManagedLoginBranding` and `DeleteManagedLoginBranding` answered `InvalidAction`. A branding is now kept per app client with AWS's checks in AWS's order, and `AWS::Cognito::ManagedLoginBranding` deploys in CloudFormation. Contributed by @toby6578. - **ALB — the `authenticate-oidc` signing key is served** — the PEM key that signs `x-amzn-oidc-data` is now served by `kid` on `public-keys.auth.elb..amazonaws.com/` and `/_ministack/elb/public-keys/`; an unknown `kid` answers 403 `AccessDenied`. Reported by @boesing. ### Changed - **botocore 1.43.124** — the pinned botocore, whose models MiniStack reads for request and response shapes, moves from 1.43.106 to 1.43.124. ### Fixed - **S3 and S3 Tables — Object Lock, multipart and metadata tokens** — with `PERSIST_STATE=1` and `S3_PERSIST=1`, retention and legal holds now survive a restart. `CompleteMultipartUpload` answers `InvalidPartOrder`, `MalformedXML` and `InvalidPart` for out-of-order, empty or ETag-less part lists. S3 Tables keeps one `versionToken` per table and answers `ConflictException` for a stale one. - **Cognito — refreshes, codes and invitations** — `GetTokensFromRefreshToken` now requires a confidential client's secret and refuses an expired token ("Refresh Token has expired"). `AdminCreateUser` `RESEND` issues a new temporary password, sign-up and reset codes go where AWS sends them, and destinations mask as `k***@e***`. Contributed by @toby6578. - **ALB — `authenticate-oidc` refreshes the access token** — the session kept an expired access token for its whole timeout. It now refreshes the token and user claims from the IdP, signs the user in again when it cannot, and passes `AuthenticationRequestExtraParams`. Reported by @boesing. - **ALB — the data plane finds load balancers in every account and region** — a request by `DNSName`, `.alb.localhost` or `/_alb//` found only the default account's load balancers and fell through to S3. Every account and region is now searched, preferring the request's own. Contributed by @kharabasz. - **ALB — `/_alb//` selects the load balancer whatever the `Host`** — a `Host` naming another load balancer won and kept the `/_alb//` prefix on the path. The path now selects the load balancer and `Host` only feeds its listener rules. Reported by @skialpine. - **EventBridge — `PutEvents` through a global endpoint** — `EndpointId` was ignored. Endpoints now get an `EndpointId` and `EndpointUrl`, `PutEvents` delivers in the primary region with the endpoint ARN in `resources` and replicates to the secondary bus, and `CreateEndpoint` and `UpdateEndpoint` make AWS's checks. Reported by @kharabasz. - **Core — SigV4a requests run as the signing account with `AUTH` unset** — a SigV4a (`AWS4-ECDSA-P256-SHA256`) request, such as `PutEvents` with `EndpointId`, ran as `000000000000`. Its access key now names the account as a SigV4 one does. Contributed by @kharabasz. - **ACM — certificate `Options`** — `RequestCertificate` dropped `Options`; they are now stored with AWS's defaults (`ENABLED` logging, `DISABLED` export). `UpdateCertificateOptions` keeps members not sent, and both operations answer AWS's `SerializationException`, `ValidationException` and `InvalidStateException`. Contributed by @kharabasz. - **EFS — file system policies and creation tokens** — `PutFileSystemPolicy` added an `Id` and a random `Sid`; policies now come back in AWS's canonical form and malformed ones answer `InvalidPolicyException`. A reused `CreationToken` answers 409 `FileSystemAlreadyExists`. Contributed by @kharabasz. - **Auto Scaling — `SpotInstancePools`, filters and deletes** — `SpotInstancePools` now defaults to 2 only for `lowest-price` and is refused with any other strategy; updates keep unsent `MixedInstancesPolicy` members. Describe calls apply their `Filters` and name lists, and deleting a group with instances needs `ForceDelete`. Contributed by @kharabasz. - **API Gateway — imported OpenAPI documents keep `ANY` methods and parameters** — `ImportRestApi`, `PutRestApi` and an `AWS::ApiGateway::RestApi` `Body` skipped `x-amazon-apigateway-any-method` and an operation's `parameters`. They now become an `ANY` method and `method.request.*` parameters. Contributed by @mishukdutta-cz. - **Lambda — MiniStack's failures and handler errors as AWS reports them** — MiniStack's own failures answered 200 with a "Mock response"; they now answer 500 `ServiceException`. Local handler and init errors carry the runtime's error document (`Runtime.ImportModuleError`, `Runtime.HandlerNotFound`, ...), with the exception's own type. - **Lambda — exiting runtimes and Docker networks** — a runtime that exits answers `Runtime.ExitError` "Runtime exited with error: exit status N". A containerised MiniStack without `DOCKER_NETWORK` starts Lambda containers on its own network instead of the unreachable default bridge. Reported by @kharabasz. - **Lambda — the local Node shim has `ListTagsCommand` and `Lambda.send()`** — Amplify Gen 2 deploys failed with `ListTagsCommand is not a constructor` under `LAMBDA_EXECUTOR=local`. Both now exist, matching `@aws-sdk/client-lambda`. Contributed by @bpmiranda3099. - **ECS and RDS — images from MiniStack's ECR and Aurora volumes** — on the containerd image store, ECS tasks pinned to a digest failed "pull access denied for sha256"; they now run, and Lambda, AgentCore and CodeBuild images load from MiniStack's ECR too. With `RDS_PERSIST=0`, Aurora storage volumes are labelled and removed. Reported by @kharabasz. - **Docker-backed services — taken host ports are skipped** — a containerised MiniStack saw ports other containers publish as free, so RDS, ElastiCache, OpenSearch, EKS, MWAA and DocumentDB containers failed "port is already allocated". Those ports are now skipped and a lost race retries the next port. Reported by @kharabasz. - **DSQL, DocumentDB and MWAA — tenants and volumes** — DSQL clusters are kept per account and region, DocumentDB container names carry account and region so one tenant can't replace another's, and `MWAA_PERSIST`/`DSQL_PERSIST` volumes are labelled and removed with their resource. - **AppSync, API Gateway domains and CloudFormation signals — reached from any account** — API-key GraphQL requests, AppSync Events, custom domains and wait-condition signals found only the default account's resources. They now run in the owner's account and region. - **Error codes and statuses are AWS's** — SNS, ElastiCache, DocumentDB and CloudWatch used shape names as wire codes (SNS now `InvalidParameter`, `ResourceNotFound`). CloudTrail, Transfer, Backup and Bedrock errors are 400, OpenSearch `ResourceNotFoundException` is 409, and IoT and Firehose internal errors are 500. - **Requests keep what they send** — about 40 services, among them ALB, Auto Scaling, EC2, ECS, RDS, ElastiCache, DynamoDB and Glue, dropped create and update parameters. They are now stored, returned and updatable, network and gateway load balancers get `net/` and `gwy/` ARNs, and updates keep or replace what AWS does (SSM `PutParameter` policies, RDS pending changes; Kinesis resharding closes parent shards). - **Responses carry AWS's members and pages** — responses are trimmed to botocore's output shapes, without internal members or `null`s. List and Describe calls honour page sizes and return the token, omitted on the last page. SES v2 `GetEmailIdentity`, SSM `Policies`, Cloud Map `DiscoverInstances` and Bedrock `GetGuardrail` match AWS. - **IAM, CloudControl and WAFv2** — attaching a policy that does not exist answers `NoSuchEntity`, CloudControl uses the type's primary identifier, and `ListResourcesForWebACL` filters by `ResourceType`, defaulting to `APPLICATION_LOAD_BALANCER`. - **Query and XML responses escape `&` and `<`** — Auto Scaling, ALB and EC2 values such as a tag `R&D` made every later Describe for the account unparseable. They are now escaped. ### Security - **Aurora DSQL — the backend Postgres is no longer on every interface** — with `DSQL_STRICT=1` each cluster's trust-auth Postgres was published on `0.0.0.0`. It is now unpublished on MiniStack's network, or `127.0.0.1` only for a host-run MiniStack. Contributed by @toby6578. - **EventBridge — `DescribeConnection` no longer returns secrets** — it returned the stored `ApiKeyValue`, OAuth `ClientSecret` and basic-auth `Password`, which AWS never returns. - **Containers follow MiniStack's binding** — RDS, ElastiCache, OpenSearch, MWAA, EKS, DocumentDB and ECS task ports were published on every interface even with MiniStack bound to `127.0.0.1`; they now follow it. ## [1.5.37] — 2026-11-03 ### Added - **Glue — table optimizers** — `CreateTableOptimizer`, `GetTableOptimizer`, `UpdateTableOptimizer`, `DeleteTableOptimizer`, `BatchGetTableOptimizer` and `ListTableOptimizerRuns` answered `InvalidAction`. Optimizers are now stored per Iceberg table and type with AWS's defaults and errors, and dropping a table or database removes them. They never run. Reported by @lucasmfraser. - **ALB — hosts resolve through Route 53 alias records** — the data plane found a load balancer only by its `DNSName` or `.alb.localhost`. A host with an `A`/`AAAA` alias record in a public hosted zone, exact or wildcard (`*.example.com`, the most specific name winning), now reaches the load balancer the record targets, so one ALB can serve many hostnames. Reported by @boesing. - **Testcontainers — .NET example** — `Testcontainers/dotnet-testcontainers` runs MiniStack from Testcontainers for .NET with the AWS SDK for .NET. ### Fixed - **ElastiCache — user groups reach the engine** — user groups on a replication group or serverless cache were never applied, so commands ran as the open `default` user. The users now reach the engine on every change, `default` is off unless a group has one, and users can't run `ACL` writes or `CONFIG`. A change restarts the engine, dropping open connections. Contributed by @chris-plucker. Reported by @kharabasz. - **ElastiCache — user group members and the built-in `default` user** — `ModifyUserGroup` and `CreateUserGroup` accepted current members, non-members, unknown users and duplicates; they now refuse them in AWS's order and messages. Every account has the built-in `default` user, which "can't be modified." or "can't be deleted.", and `DeleteUser` takes a user out of its groups. Reported by @kharabasz. - **ElastiCache — user channels and `&` in access strings** — a user with a selector and no top-level channel rule, such as `on ~* +@all (+get ~k)`, got every channel outside its selectors; it now gets none, as on AWS. Responses escape `&` and every other value, which botocore could not parse. Contributed by @kharabasz. - **ElastiCache — a Redis OSS user group needs a `default` user** — `CreateUserGroup` and `ModifyUserGroup` accepted a Redis group with no user named `default`; they now answer `DefaultUserRequired` "Redis user group needs to contain a user with the user name default." `ModifyUserGroup` also applies an `Engine` change to `valkey`, which lifts the rule. Contributed by @kharabasz. - **ElastiCache — `ModifyUser` applies `AppendAccessString`** — the appended rules were ignored. They are now applied, the result stored with rules ordered and merged; refused rules answer `InvalidParameterValue`, and sending it with `AccessString` answers `InvalidParameterCombination` "Both AccessString and AppendAccessString provided together. Pass either one of them." Contributed by @kharabasz. - **CloudFormation — `AWS::ElastiCache::UserGroup` updates and ElastiCache failures** — an update changing the users or `Engine` leaves the group with exactly the template's users; one changing only tags or order keeps changes made outside the stack. A user listed twice fails validation ("#/UserIds: array items are not unique"). Failures read `Resource handler returned message: " (Service: ElastiCache, …)"`, as on AWS. Contributed by @kharabasz. - **DynamoDB — a value SET at several paths is stored once per path** — `SET a = :v, b = :v`, `SET a = src, b = src`, `if_not_exists`, `list_append(:l, :l)` and PartiQL `UPDATE ... SET` stored one shared value, so a later nested write to one path showed up at the others. Each path now gets its own copy. Contributed by @toby6578. - **ECS — task definition secrets** — `AWS::ECS::TaskDefinition` converted only a few container fields, so `Secrets` were never injected and `RuntimePlatform` and `EphemeralStorage` were dropped; every nested property now reaches the ECS API's form. An SSM `SecureString` secret reaches the container decrypted, not as its stored `ENCRYPTED:` form. Reported by @dimazuien. - **ECS — tasks run images from MiniStack's own ECR** — a task whose image was a MiniStack ECR `repositoryUri` was pulled from the real `*.dkr.ecr.*.amazonaws.com` host. ECS now loads it from MiniStack's registry for the host's platform, and under `AUTH=true` another account's repository needs a policy allowing the pull. Reported by @kharabasz. - **CloudFormation — a `secretsmanager` dynamic reference reads a secret in another account** — a reference by ARN looked only in the stack's account. It now resolves in the account the ARN names, and under `AUTH=true` only when the secret's policy and its customer managed KMS key allow the caller, as on AWS. Contributed by @mishukdutta-cz. - **CloudFormation and Lambda — files in another account's bucket** — a `TemplateURL`, a nested stack, an `AWS::Include` `Location`, a state machine `DefinitionS3Location` or Lambda code and layers in a bucket another account owns were looked for only in the caller's account. They are now read when the owner's bucket ACLs or policy allow it, as an S3 `GetObject` would be. Contributed by @mishukdutta-cz. - **Lambda — a declared architecture pins the container platform** — a CloudFormation or SAM function ran on the host's platform whatever its `Architectures` said. It now runs the declared platform; a host that cannot run it falls back once and remembers, and `--platform` in `LAMBDA_DOCKER_FLAGS` wins. Contributed by @toby6578. - **Lambda — cold starts** — the tar copied into a new container stayed in memory until a full garbage collection, so bursts of cold starts grew MiniStack by hundreds of MB; it is now freed when the copy ends. Concurrent cold starts of one function no longer collide on the context-ARN shim. Contributed by @skialpine. Reported by @chandra-purbia. - **Containers — failed and abandoned ones are cleaned up** — a Lambda container whose start failed after `create` was left behind, and a Docker timeout was taken for an unrunnable platform. Stopped Lambda, Glue, CodeBuild, DSQL and AgentCore containers are now reaped, and spawned containers carry MiniStack's Testcontainers session labels so Ryuk can remove them. Contributed by @kharabasz. - **EC2 — port ranges are ignored where the protocol covers all ports** — the Terraform provider revokes a new group's default egress rule as `-1` with ports `0`, which matched nothing, so a later allow-all rule lost its description and tags. `-1` and protocols other than tcp, udp, icmp and icmpv6 now ignore `FromPort`/`ToPort`, as botocore documents. Contributed by @kharabasz. - **RDS — cluster endpoints** — under `MINISTACK_RDS_PUBLIC_ENDPOINT`, a cluster's endpoints and port changed with its first instance, so Terraform showed drift; they are now reported from `CreateDBCluster`. The global writer endpoint now resolves to the writer on the Docker network, follows switchover, failover, rename and removal, and is in every PostgreSQL member's certificate. Contributed by @kharabasz. - **Step Functions — Map states** — a JSONata Distributed Map now evaluates `Items`, `ItemSelector`, `MaxConcurrency` and `Output`, and `ItemBatcher` gives each child one batch as `{"BatchInput", "Items"}`, up to 256 KiB by default. An Inline Map with `ItemReader`, `ItemBatcher` or `ResultWriter` fails with `States.Runtime` ("…not supported for INLINE maps"), which no `Catch` or `Retry` handles, as on AWS. Contributed by @mishukdutta-cz. - **Step Functions — stops and `.sync` children** — after `StopExecution`, a `Wait` kept sleeping and branches kept running, so events landed after `ExecutionAborted`; nothing follows it now. A failed, stopped or timed-out `.sync` child fails the parent with `States.TaskFailed` and the child's `DescribeExecution` as the cause, as on AWS. Contributed by @mishukdutta-cz. ## [1.5.36] — 2026-11-02 ### Added - **CloudFormation — `AWS::Events::Archive`** — a template with an EventBridge archive was refused as an unrecognized resource type, though the archive API itself was supported. It now creates the archive: `Ref` is the archive name, a generated one is the logical id cut to 35 characters, `-` and 12 letters and digits, and `Fn::GetAtt Arn` is its ARN; `Fn::GetAtt` on any other property rolls the stack back with AWS's "must be a readonly property in schema". The event pattern is stored compact, with non-ASCII characters as written and each object's keys in the order AWS stores them. A changed `Description`, `RetentionDays`, `EventPattern` or `KmsKeyIdentifier` updates the archive in place, and one left out of the template keeps its value (an empty `KmsKeyIdentifier` clears the key); an update that leaves none of the first three fails with the handler's message, so rolling an update back to such a template ends `UPDATE_ROLLBACK_FAILED`, as on AWS. A new `ArchiveName` replaces the archive, a new `SourceArn` replaces a generated one and is refused for a custom name, and a stack delete removes it. Early Validation refuses a template that breaks the resource schema (a missing `SourceArn`, an `ArchiveName` too long, too short or outside its pattern, a value of the wrong type, an unsupported property, a `KmsKeyIdentifier` over 2048 characters) and a new archive whose name is taken, with AWS's messages and in AWS's order. The handler refuses what the schema lets through, as on AWS: a name or `SourceArn` outside the API's pattern, a negative `RetentionDays`, a KMS key that does not exist, and relays EventBridge's own refusals (a taken name, a bus that does not exist, an invalid pattern) in its `Resource handler returned message` form with the SDK's suffix. Measured against a real account in eu-west-1. Contributed by @toby6578. - **CloudFormation — `AWS::CloudFormation::StackSet` with one stack instance in its own account and Region** — a template with a StackSet was refused as an unrecognized resource type. A `SELF_MANAGED` StackSet whose one `StackInstancesGroup` targets the stack's own account and Region now deploys its inline `TemplateBody` as a stack instance through the nested-stack engine, which updates it, rolls a failed update back with the stack and deletes it. `Ref` returns the `StackSetId`; `DescribeStackSet` (by name, or by `StackSetId` also once deleted) and `ListStackInstances` answer with the shapes of a real-AWS capture. Any other StackSet fails the resource with an error naming what is deployed. Contributed by @chris-plucker. - **S3 Control — account-level public access block** — `PutPublicAccessBlock`, `GetPublicAccessBlock` and `DeletePublicAccessBlock` on `/v20180820/configuration/publicAccessBlock`, which answered `InvalidURI`. The configuration is held per account and applies in every region, and its settings apply to the account's buckets with their own (`BlockPublicPolicy` refuses a public bucket policy); `DeletePublicAccessBlock` is authorized as `s3:PutAccountPublicAccessBlock`. An unset `GetPublicAccessBlock` answers 404 `NoSuchPublicAccessBlockConfiguration` carrying `` inside ``, and an unsupported method 405 `MethodNotAllowed` with `ResourceType` `ACCOUNT_PUBLIC_ACCESS_BLOCK`. Responses and errors verified against a real AWS account. Contributed by @pingedbrain. - **SSM — documents and automation executions** — `CreateDocument`, `DescribeDocument`, `GetDocument`, `ListDocuments`, `DeleteDocument`, and `StartAutomationExecution`, `GetAutomationExecution`, `DescribeAutomationExecutions`, `StopAutomationExecution`, which answered `InvalidAction`. Documents are stored per account and region with AWS's real shapes: `Hash` is the SHA-256 of the verbatim content, `Status` goes `Creating` → `Active`, `PlatformTypes` defaults to all three platforms, `CreatedDate` is sent as epoch seconds, `GetDocument` returns `DocumentFormat` `JSON` by default with the content re-serialized in AWS's canonical JSON layout, and a document's declared `parameters` appear in the description. Content is validated on create: unparsable JSON/YAML answers `InvalidDocumentContent` with AWS's "not well-formed" messages, an Automation document without `mainSteps` `Missing steps in "mainSteps".`, an unknown step action `Unknown action: `, a bad `DocumentType` AWS's `ValidationException`, a duplicate name `DocumentAlreadyExists`, and a name with a prefix AWS reserves (`aws`, `amazon`, `amzn`, `AWSEC2`, `AWSConfigRemediation`, `AWSSupport`) is refused. Executions build real `StepExecutions` from the document's `mainSteps` (one `StepExecutionId` each, inputs JSON-stringified with `{{ param }}` references resolved from declared defaults and passed `Parameters`), expose `CurrentStepName`/`CurrentAction` while running, and run the steps they can: `aws:sleep` waits its ISO-8601 duration, `aws:executeAwsApi` dispatches into the emulated `ssm` API, `aws:runCommand` dispatches `SendCommand`; a step MiniStack cannot execute fails the execution with AWS's `FailureMessage`/`FailureDetails` shape instead of reporting a fabricated success, and `StopAutomationExecution` lands `Cancelled`; under `AUTH=true` a step calls the API with the permissions of the document's `assumeRole`, or of the caller, so a step the caller may not run fails with `AccessDeniedException`. `StartAutomationExecution` answers `AutomationDefinitionNotFoundException` for a document the account doesn't hold and `InvalidAutomationExecutionParametersException` for undeclared parameters. Responses and errors verified against a real AWS account. Contributed by @pingedbrain. ### Fixed - **API Gateway — REST, HTTP and WebSocket APIs answer callers from any account** — an execute-api call reached an API only in the account its access key selected, so an unsigned call, which MiniStack serves as the default account, or a call signed by another account answered 404 `{"message": "Not Found"}` for an API another account owns. On AWS an execute-api URL reaches its API whatever the caller (captured on AWS): a method without authorization answered 200 unsigned, with another account's `Authorization` header and when signed by another account. The call now runs as the API's owner account, and the caller is authenticated in its own account. Under `AUTH=true` an `AWS_IAM` method answers a caller from another account that no REST API policy grants with 403 `AccessDeniedException` `{"Message": "User: is not authorized to access this resource"}`, as AWS does, and a policy allowing that account lets it in. An HTTP or WebSocket API is served as its owner the same way. Contributed by @chandra-purbia. - **CloudFormation — validation and provisioning errors carry no `OperationStatus`** — `DescribeEvents` gave a create or update's `VALIDATION_ERROR` and `PROVISIONING_ERROR` events `OperationStatus` `FAILED`, which AWS's don't have. Measured against a real account in eu-west-1. Contributed by @toby6578. - **CloudFormation — change sets run Early Validation** — a change set whose template fails pre-deployment validation was created and failed only on execution; `CreateChangeSet` now checks the resources it adds or modifies and fails it as AWS does: `FAILED` with "The following hook(s)/validation failed: [AWS::EarlyValidation::...]", naming the `ResourceExistenceCheck` and `PropertyValidation` hooks in the order of their first errors, keeping its changes. `DescribeEvents` for the change set (`OperationType` `CREATE_CHANGESET`) lists, newest first, its outcome, its validation errors by logical id and its start, and the stack's own events don't include them; a `CREATE` or `UPDATE` change set that succeeds has its start and `SUCCEEDED`, and one with no changes has none. `DisableValidation` skips it. `ExecuteChangeSet` on a failed change set answers AWS's "cannot be executed in its current status of [FAILED]". AWS let some invalid in-place changes through to fail at execution, from a change set or `UpdateStack`, and refused others at validation; MiniStack refuses them all at validation. Measured against a real account in eu-west-1. Contributed by @toby6578. - **CloudWatch Logs — every stored event has an `eventId`** — events written by a Lambda, a CodeBuild build or a DynamoDB import came back from `FilterLogEvents` without the `eventId` AWS always returns, so `aws logs tail --follow` stopped with `KeyError: 'eventId'` on a Lambda's log group. Contributed by @chandra-purbia. - **Cognito — a failing PreTokenGeneration Lambda fails the request** — a trigger that returned an error, including running past its own timeout, was logged and the token issued without its claims, and one that could not be invoked did the same unless `MINISTACK_COGNITO_PRETOKEN_STRICT=1` turned either into a 500. As on AWS, `InitiateAuth`, `RespondToAuthChallenge`, the refresh flows and `/oauth2/token` now answer 400 `UserLambdaValidationException` ` failed with error .` for the first and `UnexpectedLambdaException` for the second; `/oauth2/token` carries the text and code in `error`. `MINISTACK_COGNITO_PRETOKEN_STRICT` is removed. Contributed by @ryuzo-hayashi. - **Cognito — PreSignUp and CustomMessage Lambda errors** — a Lambda that returned an error failed the request with its raw error body as the message; it is now AWS's `UserLambdaValidationException` text, `PreSignUp failed with error .` and `CustomMessage failed with error .` - **ElastiCache — replication group endpoints after a restart** — with persisted state, a replication group's containers were respawned on restart but its `PrimaryEndpoint`, `ReaderEndpoint`, members' `ReadEndpoint` and `ConfigurationEndpoint` kept the old container's address; they now report the new one, as cache clusters already did. Reported by @chris-plucker. - **EventBridge — an archive created without a description or a pattern has neither** — `DescribeArchive` returned `"Description": ""` and `"EventPattern": ""`; it now leaves both keys out, as AWS does. Contributed by @toby6578. - **EventBridge — `CreateArchive` refusals** — an archive on an event bus that does not exist was created; it now answers `ResourceNotFoundException` "Event bus does not exist.", and a taken name's `ResourceAlreadyExistsException` ends with a period, as AWS's does. Contributed by @toby6578. - **EventBridge — `PutEvents` to a bus ARN in another region** — an entry naming an event bus ARN in a region other than the request's failed on its own with `ResourceNotFoundException`. AWS refuses the whole request instead: it answered 400 `ValidationException` "Cross-region api call is not allowed." for a bus in the caller's own account (captured on AWS). `PutEvents` now answers the same, before any entry is delivered. Contributed by @chandra-purbia. - **EventBridge — rule targets in another account** — `PutTargets` accepted an SQS (or other) target in another account without a `RoleArn`, and the events were then silently dropped. As on AWS, it now answers `ValidationException` "RoleArn is required for target ." for such a target in any region, and with an execution role an SQS target in another account of the same region receives the events, as AWS's cross-account targets do, and under `AUTH=true` only when the queue's policy allows that role. A target in another region is still accepted and not reached. Contributed by @chandra-purbia. - **EventBridge — rule targets that are event buses in another account or region** — `PutTargets` accepted such a target and every event was then dropped ("event bus … not found"). An event now reaches the target bus's rules in its owner's account and region, keeping its `account` and `region`; crossing into another region gives it a new id and time. As on AWS, a forwarded event reaches another bus in the same region only once and crosses regions only once (after which it may make one more same-region hop), which also stops a chain of rules from looping, so the per-rule recursion guard is gone. `PutTargets` answers AWS's errors for event bus targets: after its existing ARN checks, 400 `AccessDeniedException` `Access to the resource is denied. Reason: Cross-account pass role is not allowed.` for another account's role; then, target by target, `Source EventBus and Target EventBus must not be the same.` for the rule's own bus and `Retry policy is not supported for Event bus targets.` for any `RetryPolicy`; then `RoleArn is required for target .` for any bus target without a role, the rule's own account and region included (it was `RoleArn is required`, and only for another account or region). CloudFormation's `AWS::Events::Rule` now runs `PutTargets`' checks on create, as it did on update, so a target that is not a well-formed ARN of a supported service now fails the create too. With `AUTH=true` the `RoleArn` must name the rule account's role exactly, its trust policy must let EventBridge assume it for the rule (conditions see the rule's account as `aws:SourceAccount` and its ARN as `aws:SourceArn`), and it must be allowed `events:PutEvents` on the bus, with `aws:RequestedRegion` the bus's region; a Deny in the bus's policy refuses it, and a bus in another account must also allow it, with `events:eventBusInvocation` `true` for its conditions. MiniStack does not model target dead-letter queues, so a refused event is dropped and logged with the `ERROR_CODE` AWS records (`NO_PERMISSIONS`, `THIRD_ACCOUNT_HOP_DETECTED` or `THIRD_REGION_HOP_DETECTED`). A schedule whose target is an event bus still publishes to it as before. Recorded with three accounts in eu-west-2, us-east-1 and us-west-2. Contributed by @toby6578. Reported by @lucasmfraser. - **KMS — keys in other accounts, missing keys and denials answer as AWS does** — another account's key named by key ARN or alias ARN, or by the ciphertext `Decrypt` is given, is now governed by its key policy in both auth modes. A refusal names the key when it exists and not when it does not; operations AWS does not serve across accounts answer `This operation cannot be called cross account`; another Region's ARN answers `Invalid arn `. A key or alias that does not exist answers `NotFoundException` before any permission check, worded as AWS words it, and a denial no policy allows is HTTP 400 naming the key. `DescribeKey` carries `AWSAccountId`, `GetKeyRotationStatus` carries `KeyId` (and no period while rotation is off), and the default key policy has AWS's layout. Recorded with two accounts in us-east-1. Contributed by @Jolley71717. Reported by @kharabasz. - **Lambda — `nodejs24.x` refuses callback-based handlers** — a handler taking a callback ran on `nodejs24.x`; as AWS's Node.js 24 runtime does, a handler with three or more parameters that is not a response-streaming handler now fails with `Runtime.CallbackHandlerDeprecated` "ERROR: AWS Lambda has removed support for callback-based function handlers starting with Node.js 24. …", with the local executor and with `LAMBDA_EXECUTOR=docker`, and local workers carry `AWS_EXECUTION_ENV` (`AWS_Lambda_`) as AWS's runtimes do. - **Lambda — Node.js functions in a `"type": "module"` package under `LAMBDA_EXECUTOR=docker`** — the context shim MiniStack adds to a Node function was written as `_msctx_shim.js`, which Node loads as an ES module when the package's `package.json` says `"type": "module"`, so every invoke failed with `ReferenceError: require is not defined in ES module scope`. It is now `_msctx_shim.cjs`, which Node always loads as CommonJS, and the function runs as it does on AWS. Contributed by @Jolley71717. Reported by @evan-burrell. - **Lambda — a function with no declared architecture after an arm64 one** — with `LAMBDA_EXECUTOR=docker`, invoking an `arm64` function pulled the arm64 image under the shared runtime tag, and a function that declared no architecture then ran that image on an x86 host and failed with `exec format error`; the host's image is now pulled back and run. - **RDS — a cluster master password change is visible before it settles** — `ModifyDBCluster` with `MasterUserPassword` changed the password at once and every `DescribeDBClusters` reported `available`, so a client waiting to observe the reset never saw it. As captured from real AWS, the `ModifyDBCluster` response and the first `DescribeDBClusters` show the cluster `available` with `PendingModifiedValues.MasterUserPassword` `****`, the next reports `resetting-master-credentials` (still pending), and later ones `available` with nothing pending. A password change on a stopped cluster now fails with `InvalidDBClusterStateFault` ("Db cluster cannot be in the stopped state."), as AWS does. Contributed by @chris-plucker. - **RDS — default Aurora cluster parameter groups** — `DescribeDBClusterParameterGroups` and `DescribeDBClusterParameters` answered `DBParameterGroupNotFound` for a default group such as `default.aurora-postgresql16`, and a new cluster reported `default.aurora-postgresql` with no version; each Aurora family in the engine-version catalog now has its `default.` group, and a cluster created without a parameter group reports its engine version's default, as AWS names it; an unfiltered `DescribeDBClusterParameterGroups` lists a default group only once it exists in the account (described by name or used by a cluster), as AWS does, and a major engine upgrade moves a cluster on the default group to the target version's default while keeping a custom group (the upgrade is reported as pending, then `upgrading`, then done, and member instances on the old default group follow), and a default group cannot be modified (`InvalidParameterValue` "Cannot modify a default parameter group.") or deleted (`InvalidDBParameterGroupState` "Default DBClusterParameterGroup cannot be deleted: "), while a reset succeeds; deleting a cluster parameter group that does not exist answers "DBClusterParameterGroup not found: ". Contributed by @chris-plucker. - **RDS — `ModifyDBCluster` major upgrades need `AllowMajorVersionUpgrade`** — a change to another major version went through without it; it now answers 400 `InvalidParameterCombination` "The AllowMajorVersionUpgrade flag must be present when upgrading to a new major version.", as AWS's Aurora upgrade guide shows. - **S3 — `Tagging` on `CreateMultipartUpload`** — the `x-amz-tagging` header was ignored, so an object uploaded in parts had no tags, including S3-to-S3 copies by `aws s3 cp` of objects large enough to copy in parts. The tags now land on the completed object's version, decide tag-filtered replication rules and carry to the replica, as with PutObject; more than 10 answer 400 `BadRequest` "Object tags cannot be greater than 10" at create time, and an untagged multipart upload that overwrites a tagged object leaves it without tags, as on AWS. Contributed by @zalefin. - **S3 — an overwritten object's tags and ACL** — `PutObject` and a POST upload without tags or an ACL kept the overwritten object's, so `GetObjectTagging` and `GetObjectAcl` reported them on the new object; as on AWS, the new object starts with no tags and the default ACL. - **S3 Tables — Iceberg `last-column-id` counts nested fields** — a table created through the Iceberg REST catalog reported the number of top-level fields as its `last-column-id`, and `add-schema` advanced it to the highest top-level id, so with a list, map or struct column a client's next column reused a nested field's id and Trino's `ADD COLUMN` failed with `Multiple entries with same key`. It is now the highest field id anywhere in the schema, a list's `element-id` and a map's `key-id` and `value-id` included, as on AWS. Contributed by @Jolley71717. Reported by @Wazabit. - **S3 Tables — Iceberg REST `dropTable` and `dropNamespace`** — `DELETE …/namespaces/{ns}/tables/{table}` and `DELETE …/namespaces/{ns}` answered `Unknown Iceberg REST path`, so Trino's `DROP TABLE` failed. A table is now dropped, with its metadata files, when the call sets `purgeRequested=true`, so a table created again under the same name starts empty; without the flag the answer is AWS's `purge_enabled` error. A namespace that still holds tables answers `namespace_not_empty`. `HEAD` on a namespace is served, and `HEAD` on a table or namespace answers 204 as AWS does. Contributed by @Jolley71717. Reported by @Wazabit. - **S3 Tables — Iceberg REST `createTable` location and `stage-create`** — a `"location": null`, which Trino sends for a table without a location, was stored as the table's location, so Trino failed with `Cannot parse to a string value: location: null`. As on AWS, the location is now always the one S3 Tables assigns, whatever the client sends, and a create without `stage-create`, or with a null one, answers 400 `required_field_is_null` "stage-create is a required field and cannot be null". Reported by @Wazabit. - **S3 Tables — Iceberg REST `createTable` renumbers field ids** — the client's field ids were kept; as on AWS they are now renumbered from 1, each struct's fields before their nested types, with `last-column-id`, the partition spec's and the sort order's `source-id`s following the new ids, and a `write-order` becomes the table's sort order. - **Secrets Manager — a replicated secret reports its own `PrimaryRegion`** — `DescribeSecret` and `ListSecrets` returned `PrimaryRegion` only for a replica, so a client reading the Region of a secret it replicated got nothing; the primary of a replicated secret now reports its own Region, as AWS does, a replica still reports its source Region, and a secret that is not replicated still has none. Contributed by @chris-plucker. - **Step Functions — `ecs:runTask.sync` fails with the task** — the state waited for the task to stop and then always succeeded, with the whole DescribeTasks response as its result. As on AWS, a task whose essential container exits non-zero, or that never starts, now fails the state with `States.TaskFailed`, the stopped task as JSON in PascalCase (epoch-millisecond timestamps) as the cause, so `Retry` and `Catch` apply; otherwise the state's result is that task document. Reported by @lucasmfraser. ## [1.5.35] — 2026-10-30 ### Added - **API Gateway — `PutRestApi`** — `PUT /restapis/{id}` answered 404, so Terraform's `aws_api_gateway_rest_api` with a `body` failed; it now imports an OpenAPI or Swagger definition (JSON or YAML) in `merge` mode (the default) or `overwrite` mode, which also removes the API's authorizers, and in both modes the API takes its name from `info.title` its description from `info.description` (removed when absent) and its `version` from `info.version`. An unknown API answers `Invalid API identifier specified :`, a body that is no definition `Unable to determine OAS/Swagger version` and a bad `mode` AWS's enum validation message. `ImportRestApi` now imports its definition too, where it created an empty API named `unnamed`. Reported by @mindsers. - **API Gateway — client certificates** — `GenerateClientCertificate`, `GetClientCertificate`, `GetClientCertificates`, `UpdateClientCertificate` and `DeleteClientCertificate`, with a 6-character id, a self-signed PEM certificate (C=US, L=Seattle, CN=ApiGateway) valid for one year, tags on the certificate's ARN, and AWS's errors: `Invalid client certificate id specified` (404, and 400 for a stage's `/clientCertificateId` patch) and `Invalid patch path '' specified for op ''. Must be one of: [/description]`. Reported by @mindsers. - **API Gateway — domain name access associations** — `CreateDomainNameAccessAssociation`, `GetDomainNameAccessAssociations`, `DeleteDomainNameAccessAssociation` and `RejectDomainNameAccessAssociation` for private custom domain names, named by their `domainNameArn`, with the ARN `.../domainnameaccessassociations/domainname/+/vpcesource/` and tags on it. A duplicate, an unknown domain or a VPC endpoint EC2 doesn't hold answer 400 `BadRequestException` "The domain name access association between this VPC endpoint and domain name already exists.", "Domain not found" and " is not a valid VPC endpoint id"; rejecting an association of your own, or any after the domain is deleted, answers 404 "This private custom domain name doesn't have any domain name access associations." and keeps it. Reported by @mindsers. - **ELBv2 — listener certificates** — `AddListenerCertificates`, `DescribeListenerCertificates` and `RemoveListenerCertificates`, as on AWS: one certificate per call, `CertificateNotFound` for a certificate ACM doesn't hold, the default certificate listed last with `IsDefault` true and never removed. Reported by @kharabasz. - **IAM — service-specific credentials and server certificates** — clients that call `ListServiceSpecificCredentials` or `ListServerCertificates` got `InvalidAction`. `CreateServiceSpecificCredential`, `ListServiceSpecificCredentials`, `UpdateServiceSpecificCredential`, `ResetServiceSpecificCredential` and `DeleteServiceSpecificCredential` now answer: a CodeCommit or Keyspaces credential is a `ServiceUserName` (`-at-`) and `ServicePassword`, a Bedrock, Claude Platform on AWS, CloudWatch or CloudWatch Logs one a `ServiceCredentialAlias` and `ServiceCredentialSecret` with the `ExpirationDate` from `CredentialAgeDays`; the password or secret is returned only on create and reset, another service answers `NotSupportedService` (404), and `UserName` may be omitted by an IAM-user caller while a non-user caller without it gets `InvalidInput`. `UploadServerCertificate`, `ListServerCertificates`, `GetServerCertificate` (with its `CertificateChain`), `UpdateServerCertificate`, `DeleteServerCertificate` and `ListServerCertificateTags` keep names unique across paths, parse `Expiration` from the PEM (left out on the slim image, which has no `cryptography`), and answer `MalformedCertificate` for a body that is not a certificate. Contributed by @pingedbrain. ### Fixed - **API Gateway — custom domain name responses** — a regional domain name now has its `domainNameArn` `arn:aws:apigateway:::/domainnames/`, `certificateUploadDate` and a `d-<10 characters>.execute-api..amazonaws.com` regional name, and responses leave out the fields AWS doesn't send for the endpoint type, empty values among them; `endpointConfiguration` carries `ipAddressType` and `tags` appear on `GetDomainName`. Reported by @cupidchan. - **API Gateway — private custom domain names** — the `domainNameId` 1.5.34 gave a private domain had 8 characters where AWS's has 10; a private domain now also defaults `ipAddressType` to `dualstack`, and a `policy` statement on `execute-api:/*` is returned naming the domain's own `execute-api` ARN, as on AWS. Reported by @mindsers. - **AppConfig — `KmsKeyArn` is built from the identifier as given** — 1.5.34 resolved an alias to its key's ARN and only reported a `KmsKeyArn` for a key MiniStack's KMS held; as on AWS, a key ARN or alias ARN is kept, a key id becomes `arn:aws:kms:::key/` and an alias name `arn:aws:kms:::alias/`, without checking the key exists. A hosted version created under a profile with a key carries its `KmsKeyArn`, and `StartDeployment` of such a version answers "KmsKeyIdentifier required when deploying a hosted configuration version that is encrypted with a customer managed key (CMK)" without a `KmsKeyIdentifier`, and KMS's messages for a key that does not exist, is disabled or is in another account. Reported by @kharabasz. - **AppConfig — `ListDeployments` and tag errors** — deployments are listed newest first with `ConfigurationProfileId` and `Type` `USER`, and `ListTagsForResource`, `TagResource` and `UntagResource` answer AWS's errors for an ARN without an account id (400) and another account's ARN (403 `AccessDeniedException`). Reported by @kharabasz. - **Auth — HTTP/2 clients that sign `:authority`** — with `AUTH=true`, a request signed with an IAM user or STS session key over HTTP/2, as the JavaScript SDK v3 does for Kinesis, Bedrock Runtime and other clients, answered `SignatureDoesNotMatch`: Hypercorn passes `:authority` to the app as `host`, so it was signed as empty. A signed `:authority` now takes the `host` value. Reported by @ScriptSmith. - **Auto Scaling — `MixedInstancesPolicy`** — `CreateAutoScalingGroup` and `UpdateAutoScalingGroup` dropped it, so the group reported no launch template; it is now kept, in CloudFormation too, with the launch template's id and name filled in, `Overrides` `[]` when none are given and AWS's `InstancesDistribution` defaults, and the group then has no `LaunchTemplate`. A group with both a `LaunchTemplate` and a `MixedInstancesPolicy`, or with no launch source at all, answers "Valid requests must contain either LaunchTemplate, LaunchConfigurationName, InstanceId or MixedInstancesPolicy parameter." Reported by @kharabasz. - **Auto Scaling — launch template request checks** — a `LaunchTemplate` with both or neither of `LaunchTemplateId` and `LaunchTemplateName` answers "Valid requests must contain either launchTemplateId or LaunchTemplateName", a version other than `$Default`, `$Latest` or a number "Invalid launch template version: either '$Default', '$Latest', or a numeric version are allowed.", and an unknown id "Malformed launch template Id: " or, for a short `lt-` id or one in another region, "The specified launch template, with template ID , does not exist.", on create and update, as on AWS. Reported by @kharabasz. - **CloudFront — `UpdateFunction` returns its ETag where the SDKs read it** — AWS sends `UpdateFunction`'s ETag in a header named `ETtag`, which is where botocore and the other SDKs read it; MiniStack sent `ETag`, so an SDK client got no ETag back and Terraform's `aws_cloudfront_function` failed to publish a code change with `InvalidIfMatchVersion`. Reported by @kharabasz. - **CloudFront — Functions LIVE versions, publish, delete and precondition errors** — each stage now counts its own versions: `PublishFunction` moves LIVE to its next version, with the ETag of that version number, and leaves DEVELOPMENT's ETag unchanged, where 1.5.34 copied DEVELOPMENT's ETag to LIVE. `PublishFunction` no longer sends an `ETag` header, `DeleteFunction` of a function a distribution uses answers 409 `FunctionInUse` "Cannot delete function , it is in use by distributions", and a stale `If-Match` on publish or delete answers `PreconditionFailed` "The request failed because it didn't meet the preconditions in one or more request-header fields." Reported by @kharabasz. - **CloudFront — viewer requests to an alternate domain name** — the data plane served a distribution only at its `