I suspect that there is a problem with the Execution Engine where the authorization header value is not correctly interpreted when defined with:
{
"Authorization": "ApiKey $inputs.api_key"
}
Issue 2: Getting a 400 on a simple GET request
In Elasticsearch, many APIs do not require any request parameters or any JSON payload.
When attempting to run a Webhook Sink to run a simple request like GET _cluster/health (c.f doc), Elasticsearch returns a 400. When configured with GET and no query parameters, no JSON payload, I suspect the Webhook Sink is actually sending an empty JSON payload and this will be considered as a bad request in Elasticsearch.
I just wanted to bring these up for review and considerations for further fixes/improvements.
The string interpolation only works when the entire header value is a reference (like $inputs.api_key), not when the reference is embedded within other text (like "ApiKey $inputs.api_key").
Your workaround is a good approach - using a custom block to pre-format the authorization string:
This is likely the Webhook Sink sending an empty JSON body or Content-Type: application/json header even when no payload is configured for GET requests. Elasticsearch (and many APIs) will reject GET requests that contain any body content.
If possible, check if Elasticsearch offers a POST-based alternative for the health check endpoint, or consider using a custom HTTP block that gives you more control over the request.
The string interpolation only works when the entire header value is a reference (like $inputs.api_key), not when the reference is embedded within other text (like "ApiKey $inputs.api_key").
That is what I thought. In this case, would it make sense to have some sort of validation in the workflow itself and provide some errors/warnings to the user?
This is likely the Webhook Sink sending an empty JSON body or Content-Type: application/json header even when no payload is configured for GET requests.
I believe the Webhook Sink is actually sending an empty JSON body for a GET request when no payload is defined in the Webhook Sink block. From a logic perspective, if no payload is defined in this block, we should probably not send an empty JSON block. What do you think?
Just to clarify and readdress the ways we can fix these issues.
Issue 1 The execution engine’s selector detection only recognizes values that start with $. When you write:
{“Authorization”: “ApiKey $inputs.api_key”}
The value starts with "ApiKey ", not $, so the entire string is treated as a literal - no substitution occurs. The $inputs.api_key part is never resolved. Your workaround using a custom block works because “$steps.my_custom_block.formatted_api_key” starts with $, so it gets properly resolved. This is why the workaround with a custom block you identified works
Issue 2
Two things combine to cause this:
1. json_payload defaults to an empty dict {} when not specified
2. The request always includes the json parameter regardless of HTTP method
So for a GET request with no payload:
json_payload becomes {}
The requests library sends a body containing {} with Content-Type:
application/json
Elasticsearch (and many REST APIs) reject GET requests with a body,
returning 400
Unfortunately there’s no clean workaround within the current Webhook Sink.
Options:
Use a custom HTTP block that omits the body for GET requests
Use POST if your API supports it for the same endpoint