Closed
Description
Is there an existing issue for this?
- I have searched the existing issues
Feature description
LocalStack does not currently support overriding:
responseOverride.status
to set HTTP response statusrequestOverride.querystring
to inject query parameters into the integration request
Both work correctly in AWS API Gateway when using Velocity templates (VTL), but fail in LocalStack.
Examples
Override response status code (VTL):
#set($statusCode = $context.authorizer.statusCode)
#if($statusCode == 200)
## Mapping the parameters from the request to the backend
#foreach($param in $input.params().querystring.keySet())
#set($context.requestOverride.querystring[$param]= $input.params().querystring.get($param))
#if($foreach.hasNext) #end
#end
{
"statusCode": 200,
"message": "Valid scope found"
}
#else
#set($context.responseOverride.status = $statusCode)
{
"error": $context.authorizer.error
"statusCode": $statusCode,
}
#end
In AWS → returns HTTP 200.
In LocalStack → returns HTTP 200, or fails with:
2025-05-15T04:12:58.145 WARN --- [et.reactor-5] l.s.a.n.e.h.gateway_except : Non Gateway Exception raised: line 5, column 13: expected assignment in set directive, got: ($context.requestOverride.querystrin ... ...
Traceback (most recent call last):
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 350, in require_next_element
element = element_spec(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1077, in parse
(var_name,) = self.identity_match(self.START)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 306, in identity_match
raise NoMatch()
airspeed.operators.NoMatch
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/rolo/gateway/chain.py", line 166, in handle
handler(self, self.context, response)
File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/handlers/integration_request.py", line 119, in __call__
body, request_override = self.render_request_template_mapping(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/handlers/integration_request.py", line 186, in render_request_template_mapping
body, request_override = self._vtl_template.render_request(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/template_mapping.py", line 193, in render_request
result = self.render_vtl(template=template.strip(), variables=variables_copy)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/localstack-core/localstack/utils/aws/templating.py", line 119, in render_vtl
rendered_template = t.merge(namespace)
^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 92, in merge
self.merge_to(namespace, output, loader)
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 102, in merge_to
self.ensure_compiled()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 97, in ensure_compiled
self.root_element = TemplateBody(self.filename, self.content)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1351, in parse
self.block = self.next_element(Block)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 333, in next_element
element = element_spec(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1368, in parse
self.next_element(
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 339, in next_element
element = element_class(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1043, in parse
self.block = self.require_next_element(Block, "block")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 350, in require_next_element
element = element_spec(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1368, in parse
self.next_element(
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 339, in next_element
element = element_class(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1312, in parse
self.block = self.next_element(Block)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 333, in next_element
element = element_spec(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1368, in parse
self.next_element(
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 339, in next_element
element = element_class(self.filename, self._full_text, self.end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
self.parse()
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1291, in parse
self.assignment = self.require_next_element(Assignment, "assignment")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 352, in require_next_element
raise self.syntax_error(expected)
airspeed.operators.TemplateSyntaxError: line 5, column 13: expected assignment in set directive, got: ($context.requestOverride.querystrin ... ...
Environment
- LocalStack version: latest
- Running via: Docker / Compose / CLI
- Infrastructure: Terraform / AWS CLI
🧑💻 Implementation
No response
Anything else?
No response
Activity
localstack-bot commentedon May 15, 2025
Welcome to LocalStack! Thanks for reporting your first issue and our team will be working towards fixing the issue for you or reach out for more background information. We recommend joining our Slack Community for real-time help and drop a message to LocalStack Support if you are a licensed user! If you are willing to contribute towards fixing this issue, please have a look at our contributing guidelines.
cloutierMat commentedon May 15, 2025
Hi @pieronatan, thank you for your report of this bug in LocalStack.
I am trying to get a good understanding of your use case so I can get to the issuemore quickly. Can you tell me which integration you are using, as it sometimes impacts how ApiGw behaves with VTL template and overrides. Also, I assume you are using a lambda authorizer and using it's response in the authorizer context?
#set($context.responseOverride.status = $statusCode)
is not impacting the response, right? As this variable is only used in the response templates, not in the request templates? Did you experience something different?I believe there may be a gap in our VTL implementation when attempting to use
#set
on a dict with dynamic assignment using[$var]
. I will look into that one first as it seems to be the error you are experiencing given the following logPlease, let me know if I am missing anything.
pieronatan commentedon May 15, 2025
I'm using a Lambda authorizer that returns custom metadata via the context object, including a statusCode. In my mapping template, I dynamically override the response status based on this value using context.responseOverride.status.
Attempts to hardcode the status code (e.g., setting it directly to a fixed value) resulted in errors.
cloutierMat commentedon May 15, 2025
Thank you for the extra input I had time to run some quick test as well. I will keep you updated as the fix becomes available.
13 remaining items