What's Changed
New Contributors
- @dmgarland made their first contribution in #1775
[1.5.14] — 2026-09-20
Added
- KMS — imported key material — a key created with
Origin=EXTERNALstayed unusable because there was no way to supply its material.GetParametersForImport,ImportKeyMaterialandDeleteImportedKeyMaterialnow complete the flow: the key waits inPendingImport, all five wrapping algorithms unwrap, andExpirationModelandValidToare reported on the key. Reported by @guymahieu. - API Gateway — REST request validators, API keys, throttling and quotas are enforced — the five
RequestValidatoroperations are implemented, a method'srequestValidatorIdis applied to the body and parameters, and an API key is checked against its usage plan's rate, burst and quota. Reported by @iot-rocket. - CloudFormation — update handlers for twelve more types — a stack update of these types re-ran the create, so the resource came back under a new id or the change was lost. Each now updates in place where its reference allows, replaces otherwise, and refuses to replace a custom-named resource. Contributed by @iot-rocket.
- RDS — resource-bound IAM database authentication — a verified token is now authorized against the policy's resource, so a grant scoped to one database user stops matching another. Contributed by @Areson.
- RDS — PostgreSQL instances serve TLS — a generated CA signs a server certificate for each container, so a client connecting with
sslmode=verify-fullcompletes the handshake instead of failing.GET /_ministack/rds/ca.pemreturns that CA, the local stand-in for AWS's certificate bundle. Reported by @jayjanssen. - Bedrock Agent Runtime —
RetrieveappliesvectorSearchConfiguration.filter— the filter was parsed and ignored, so every query returned the whole knowledge base. All eleven comparators plusandAllandorAllnow select against the document's metadata, read from its.metadata.jsonsidecar. Reported by @Vidminas. - Bedrock Runtime —
toolConfigreaches the backing model — aConversecall carrying tools was proxied without them, so the model could never answer with a tool use. Tools are forwarded, and a tool call comes back as atoolUseblock, streamed ascontentBlockStartwhen the caller streams. Reported by @Vidminas. - IoT — a job execution times out —
timeoutConfig.inProgressTimeoutInMinutesand the device's ownstepTimeoutInMinuteswere stored and ignored, so an execution stayedIN_PROGRESSfor ever. An execution past its timeout is nowTIMED_OUT, and the device plane reportsapproximateSecondsBeforeTimedOutwhile it runs. - Health — the IoT mTLS listener is reported —
/_ministack/healthcarriesiot_mtls, and/_ministack/readywaits for that listener, so a consumer polling readiness no longer races the MQTT port.
Changed
- IAM — wildcard matching is case-sensitive where AWS makes it case-sensitive —
Resource,NotResource,StringLike,StringNotLike,ArnEqualsandArnLikecompared case-insensitively, so a policy namingarn:aws:s3:::MyBucketalso matchedmybucket. OnlyActionstays case-insensitive, as on AWS. - SQS — the default
MaximumMessageSizeis 1 MiB — queues were created with AWS's old 256 KiB default, so a message between 256 KiB and 1 MiB was rejected where AWS accepts it. The bound accepted bySetQueueAttributesmoves with it.
Removed
- Four timing environment variables —
TRANSCRIBE_JOB_RUN_SECONDS,GLUE_CRAWLER_RUN_SECONDS,MINISTACK_DDB_IMPORT_COMPLETE_AFTER_SECandLAMBDA_STATE_TRANSITION_SECONDSpaced emulator-only state transitions and had no AWS counterpart. The transitions keep their previous default pacing.
Fixed
- EventBridge — dynamic HTTP parameters for API destinations —
HttpParametersJSON paths went to the endpoint as literal$.strings. They now resolve against the original event, before input transformation, array indexes and wildcards included. Contributed by @dmgarland. - RDS — restarting a cluster keeps its DNS endpoint — a restart reported the container's IP in place of the
*.rds.amazonaws.comname handed out at creation, breaking connection strings and hostname-verified TLS. The restart now reports the registered network alias, and the reader endpoint derives itscluster-ro-name only when that name was registered. Contributed by @jayjanssen. - RDS Data — a PostgreSQL
SELECTreports the rows it returned —numberOfRecordsUpdatedcarried the row count for a read, where AWS reports0and leaves the rows inrecords. Contributed by @jayjanssen. - IoT — the registered-certificate event comes from the device connect —
RegisterCertificatepublished it, and an mTLS connect with an unknown certificate got CONNACK 5 with nothing created. AWS creates the certificatePENDING_ACTIVATIONon the connect, publishes the event withsourceIp, and closes without a CONNACK. Contributed by @iot-rocket. - IoT —
DescribeEndpointrefuses the retirediot:Dataandiot:Jobstypes — both returned a hostname, so a client could keep using an endpoint type AWS no longer serves. AWS answersInvalidRequestException400 and points toiot:Data-ATS; both types now get the same errors and messages. Contributed by @iot-rocket. - IoT Data — HTTPS
Publishrefuses the topics AWS refuses — any$topic was accepted, so a caller could forge$aws/events/...lifecycle events. Reserved topics now answerInvalidRequestException400 "Topic can't start with $", and the MQTT-only jobs, Device Defender and commands topics "Invalid publish to restricted topic using HTTP". Contributed by @iot-rocket. - CloudFormation —
AWS::ECR::Repositorykeeps what the template declares — scanning and encryption read back empty, lifecycle and repository policies and tags were dropped,PutImagefailed, and a delete left images behind. The resource now goes through the ECR store. Contributed by @iot-rocket. - CloudFormation — a rolled-back replacement keeps the old resource — the predecessor was deleted as soon as the replacement existed, so a later failure rolled back to a resource that was gone. It is now deleted after the update succeeds, and a rollback deletes only the replacement. Contributed by @iot-rocket.
- API Gateway — REST API gateway responses reach the data plane — a customized response was stored and never applied, so a 401 or 403 carried none of the CORS headers a CDK stack declares. Gateway errors now resolve their type, then
DEFAULT_4XX/DEFAULT_5XX, then the built-in default, with header mappings andx-amzn-ErrorType. Contributed by @iot-rocket. - API Gateway — REST API gateway errors answer with the AWS status and message — invented statuses and exception text went out. A failed authorizer is
500AUTHORIZER_FAILUREwith a null message, a missing backend500API_CONFIGURATION_ERRORInternal server error, and an unknown stage403Forbidden. Contributed by @iot-rocket. - API Gateway — a MOCK integration honours its
statusCode— the200integration response was used whatever the request template set, so a MOCK method modelling an error returned200. The template'sstatusCodenow selects the integration response byselectionPattern. Contributed by @iot-rocket. - AppConfig —
GetLatestConfigurationserves a feature-flag profile in retrieval-time format — the stored{flags, values, version}document was returned verbatim, so a client reading a flag found nothing at the top level. AAWS.AppConfig.FeatureFlagsprofile is now flattened to itsvalues, disabled flags included. Reported by @dk-tanio. - Bedrock AgentCore — timestamps are ISO 8601 strings everywhere —
CreateAgentRuntimeanswered with a JSON number whileListAgentRuntimesanswered with a string for the same field, so a typed SDK failed on one of the two. Both now match the model'siso8601format. Reported by @ykalemi. - S3 — an omitted notification configuration
Idis generated — a configuration sent without one read back without one, where AWS assigns base64 of a UUID. Reported by @jin-gizmo. - S3 — a notification configuration is stored in the form the wire uses — the request XML was echoed back, so a configuration sent with
LambdaFunctionConfigurationsread back empty for a client expecting the wire nameCloudFunctionConfiguration, which also hid a CloudFormation-declared Lambda notification. Reported by @jin-gizmo. - CloudFormation —
AWS::WAFv2::WebACLreturns theRefAWS returns — the bare id came back where AWS returnsname|id|scope, so a template passing theRefto another resource passed an unusable value. - Cognito — the OIDC discovery document follows the gateway's scheme — every endpoint in it was
httpeven withUSE_SSL=1, so the document contradicted its ownhttpsissuer and a discovery client refused it. Reported by @epcap90. - IoT — rule SQL accepts the grammar AWS accepts —
!=and==were evaluated, where AWS refuses both, and a nestedSELECTin aWHEREclause was accepted, where AWS answersUnexpected token, 'SELECT'.clientid()now resolves ton/afor a publish that did not arrive over MQTT rather than dropping the field from the projection. - IoT — the rule error action document matches AWS — a failure was reported as
{action, errorMessage}, where AWS namesfailedAction(DynamoDBv2Action,SnsAction) andfailedResource(the table, topic, queue or function the action targeted).clientIdisN/Afor a non-MQTT publish rather than empty, and the document carriessourceIp. - IoT —
CreateJobvalidates what AWS validates — aschedulingConfigtime with seconds or aZ, aninProgressTimeoutInMinutesoutside 1 to 10080, a document over 32768 characters, adocumentSourceoutside 1 to 1350, and a request naming neither a document nor a source were all accepted. Each now answersInvalidRequestExceptionwith AWS's own sentence. - IoT —
DescribeJobechoes the members it accepted —abortConfig,timeoutConfig,schedulingConfig,jobExecutionsRetryConfig,namespaceId,jobTemplateArn,documentParametersanddestinationPackageVersionswere stored and never reported, andisConcurrentandforceCanceledwere missing. Job timestamps are whole epoch seconds, not fractions. - IoT Jobs data — two device-plane answers match AWS —
UpdateJobExecutionwith a status a device cannot set answeredInvalidRequestException400 instead ofInvalidStateTransitionException409, and anexecutionNumbernaming an execution that does not exist was ignored instead of answeringResourceNotFoundException404. - Auto Scaling — a duplicate group or launch configuration returns
AlreadyExists— the wire code wasAlreadyExistsFault, the shape name rather than the code, so an SDK caught nothing. - CloudFormation —
ExecuteChangeSetreturnsInvalidChangeSetStatus— the shape nameInvalidChangeSetStatusExceptionwent out as the error code. - CloudFormation — the Rules section refuses
Fn::If— it was evaluated because the reference lists it, while a real account answersFollowing functions are not supported in the Rules block of the template: [Fn::If]. - CloudFormation — the 60 dynamic references per template quota is enforced — a template over the limit was provisioned instead of being refused.
- Lambda — an AWS-published extension layer resolves — a template referencing
LambdaInsightsExtension, the Parameters and Secrets, AppConfig or OpenTelemetry extensions orAWSSDKPandascould not deploy, because the publisher account is unknown offline. It now resolves by layer name withCodeSize0, so the extension does not run. - EC2 — a bare
-e NAMEdocker flag takes the host value — it was passed through as an empty string, where docker either forwards the host's value or omits the variable. - S3 Control — an unknown
/v20180820path answersInvalidURI— it fell through to a generic answer instead of AWS's 400 inside an<ErrorResponse>echoing the bad segment. - Signer — the
clientRequestTokenreplay cache is bounded — every distinct token was kept for ever and persisted with the service state. - CloudFormation —
DeletionPolicy: Snapshottakes a snapshot — the policy was read and never acted on, so a resource declaring it was deleted with nothing kept, and an RDS cluster or standalone instance, which AWS defaults toSnapshot, defaulted toDeletehere. Both now snapshot the resource and then delete it, on a stack delete and on an update that removes it from the template.