Skip to content

fix(http-provider): don't double-encode a templated JSON body - #6688

Open
dngr2 wants to merge 1 commit into
keephq:mainfrom
dngr2:fix/6547-http-provider-json-body
Open

fix(http-provider): don't double-encode a templated JSON body#6688
dngr2 wants to merge 1 commit into
keephq:mainfrom
dngr2:fix/6547-http-provider-json-body

Conversation

@dngr2

@dngr2 dngr2 commented Aug 12, 2026

Copy link
Copy Markdown

Fixes #6547

The bug

_query() normalises headers when they arrive as a string:

if isinstance(headers, str):
    headers = json.loads(headers)

but never does the same for body, which is then handed to requests as json=body. A workflow using a templated body renders to a JSON string:

- name: http-request
  provider:
    type: http
    with:
      url: "http://host:port"
      method: POST
      headers:
        Content-Type: "application/json"
      body: "{{ alert }}"

json= serialises it a second time, so the endpoint receives a quoted string instead of an object — with a Content-Type: application/json header that no longer describes the payload.

The fix

Parse a string body before sending, mirroring the headers handling three lines above.

Two details worth flagging for review:

  • Only an object or array is accepted. json.loads("123") does not raise — it returns an int. Converting a body of "123" into a number would be a silent change, so a bare scalar is left as text.
  • The ValueError catch is deliberate. This module imports JSONDecodeError from requests.exceptions, which is a subclass of the one json.loads raises, so catching it would not work here.

A body that is still a string afterwards goes out as data= with the caller's Content-Type, since json= would re-serialise it.

Behaviour change

This changes what reaches the endpoint for anyone currently sending a JSON string and compensating for the double encoding downstream. I believe the current behaviour is the bug rather than the contract, since it contradicts both the declared Content-Type and the handling of headers in the same function — but flagging it explicitly since it is the kind of thing that can bite silently.

Tests

New file: tests/providers/http_provider/test_http_provider_json_body.py

Written before the fix and run against unmodified main: 7 failed, 5 passed. With the fix: 12 passed. The 5 that passed throughout are the regression guards, which is the point of them.

  • templated and nested JSON strings, on POST / PUT / DELETE
  • plain text and XML bodies sent as data, not JSON-encoded
  • a bare numeric string not treated as JSON
  • regression guards: dict, list and None bodies unchanged

tests/providers in full: 65 passed. I have not run the suites needing Docker and a database locally — leaving those to CI.


Touches the same file as #6687 but different lines; whichever lands first, I am happy to rebase the other.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. Bug Something isn't working Provider Providers related issues labels Aug 12, 2026
_query() normalised `headers` when they arrived as a string but never did
the same for `body`. A workflow using `body: "{{ alert }}"` renders to a
JSON string, which was then passed to requests as `json=body` and
serialised a second time, so the endpoint received a quoted string rather
than an object.

Parse a string body before sending, mirroring the existing `headers`
handling three lines above. Only an object or array is accepted: json.loads
("123") succeeds and returns an int, and a bare scalar was almost certainly
meant as a plain-text body. A body that is still a string afterwards goes
out as `data=` with the caller's Content-Type, since `json=` would
re-serialise it.

Note this is a behaviour change for anyone currently sending a JSON string
and compensating for the double encoding downstream. The current behaviour
contradicts both the documented Content-Type and the handling of `headers`
in the same function, so it looks like the bug rather than the contract.

Adds tests for templated and nested JSON strings on POST/PUT/DELETE, plain
text and XML bodies going out as data, a bare numeric string not being
treated as JSON, and regression guards for dict, list and None bodies.

Fixes keephq#6547
@dngr2
dngr2 force-pushed the fix/6547-http-provider-json-body branch from c11b56b to 5ad6f1f Compare August 12, 2026 02:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something isn't working Provider Providers related issues size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[🐛 Bug]: HTTP provider sends double-encoded JSON when workflow body uses {{ alert }} template

1 participant