What's Changed
New Contributors
- @mgius-ae made their first contribution in #403
- @nigel-campbell made their first contribution in #405
[1.3.6] — 2026-04-20
Added
- API Gateway path-based data plane — REST + HTTP + WebSocket APIs are now reachable without
*.execute-api.localhostHost overrides:http(s)://localhost:4566/_aws/execute-api/{apiId}/{stage}/{path}(v1 + v2 HTTP + v2 WS) and the LocalStack-legacyhttp://localhost:4566/restapis/{apiId}/{stage}/_user_request_/{path}(v1). Unblocks macOS browsers (no*.localhostDNS resolution) and strict HTTP clients with no Host override. - Custom/predictable API Gateway IDs —
aws_apigatewayv2_apiandaws_apigateway_rest_apihonour anms-custom-idtag onCreateApi/CreateRestApiand pin the generatedapiId/ REST API id to the tag value. Duplicates in the same account returnConflictException(409). The LocalStackls-custom-idtag is intentionally rejected with a clearBadRequestException(400) pointing callers at the ministack-native key. Reported by @whittin3. Fixes #400 - Cognito
AWS::Cognito::UserPoolClientCFNGenerateSecret— CloudFormation-provisioned user pool clients now generate a client secret whenGenerateSecret: true, matching the native Cognito API path. Contributed by @mgius-ae (#403)
Fixed
- API Gateway v2 HTTP API —
$defaultstage treated first path segment as stage name — an API configured with the$defaultstage returned404 "Stage 'X' not found"for any request because the dispatcher always stripped a stage prefix from the URL. Stage resolution now checks the API's configured stages: strip the first segment only if it matches a real stage, otherwise route to$defaultwith the full path (matching AWS). Same fix applies to the WebSocket scope handler. Reported by @whittin3. Fixes #404 - API Gateway v2 HTTP API —
corsConfigurationignored — every OPTIONS preflight returned a hard-coded wildcardAccess-Control-Allow-Origin: *, breaking browsers usingcredentials: "include", and non-OPTIONS responses had the wildcard spliced in over whatever the Lambda set. API Gateway now serves preflights from the per-APIcorsConfiguration(403 if origin isn't inallowOrigins,Access-Control-Allow-Credentials: trueonly when configured and paired with a concrete origin), and dispatched responses carry per-config CORS headers instead of the wildcard. Reported by @whittin3. Fixes #406 - Lambda alias qualifier parsed as function name — integrations (v1 REST, v2 HTTP, v2 WebSocket) and event source mappings wired to a qualified ARN (
arn:...:function:<name>:<alias>) invoked a function whose name was the qualifier (live) and returned502 "Lambda function 'live' not found". All three dispatchers now use_resolve_name_and_qualifier+_get_func_record_for_qualifierto resolve aliases to their target version before invocation; worker pool keyed byname:qualifierso aliased vs unqualified calls don't share process state. ESM pollers (SQS, Kinesis, DDB Streams) store the qualifier on the mapping and use it on every batch. Reported by @whittin3. Fixes #407 - API Gateway v1 error responses used
typeinstead of__type— boto3 fell back to the numeric HTTP status as the error code (ClientError.response["Error"]["Code"] == "409"instead of"ConflictException"). Every JSON-protocol AWS service uses__type; v1 now matches. - SQS singular
DeleteMessage/ChangeMessageVisibilitysilently succeeded on invalid ReceiptHandle — real AWS returnsReceiptHandleIsInvalid(400); batch variants already did. Singular operations now raise the same error. Contributed by @nigel-campbell (#405)