(+) plus symbol in query parameter turns into space instead of encoding as %2B
I have checked the following:
- [X] I use the newest version of bruno.
- [X] I've searched existing issues and found nothing related to my issue.
Describe the bug
Updated bruno recently and some of old requests don't work because + sign in query parameter gets replaced by a space.
As a workaround, replacing (+) sign with %2B resolves the issue.
I'm at work so can't provide screenshot right now
.bru file to reproduce the bug
No response
Screenshots/Live demo link
N/A
Could you add some examples?
I went through this elsewhere, but its not a bug spaces can be interpreted as + or %20. https://en.wikipedia.org/wiki/Query_string
Could you provide some examples?
Hey @mroderick,
Here is an example that demonstrates this behavior:
https://github.com/user-attachments/assets/799da1d8-f158-4101-a727-c668c4c7703f
As @alifemove mentioned, this is not a bug. A query string can contain either + or %20 to represent spaces. Additionally, @abdulmahamaliyev, using %2B would be a good enhancement, and I agree with that.
I faced this bug myself today, and was thoroughly confused by it. Thought it was a bug in my code, rather than bruno.
A solution would be:
- Anything that's input in the param is treated as if it wasn't encoded yet, so if you write
+in the param it will be converted to%2B - Anything that's input in the url is treated as if it was already encoded. So if you write
+in the url, it will be converted to%20orin the param field.
But when I input a string in the param, I expect it to be treated as a string that will be encoded still, instead of verbatim copying it to the url
Workaround I created was a collection pre-request script:
const [url,params] = req.url.split('?');
if(!params) return;
const encodedParams = params.split('&').map((kv) => {
const [k,v] = kv.split('=');
return `${k}=${encodeURIComponent(v)}`;
}).join('&');
req.setUrl(`${url}?${encodedParams}`);
As this is not a bug this should be closed. The standards say that + is to be treated as a space, which is what Bruno is doing. Any workarounds being created or changes to Bruno would be going against the standards. Standards also say if you want a literal + you should use %2B, which was stated in the original issue that %2B works, because again, Bruno is working as it should.
@alifemove I agree that the + in the url should be treated as a space, as is the spec (and Bruno)
But there is also part of user expectation, that when they (me included) put a + in the param value field, to be treated as a string literal, and be encoded as such.
Hence, in my first comment here I suggested that the + in the url bar would be treated according to the spec as a whitespace, but the + in a param field, would be treated as string literal, and to be encoded.
Since as a user it's not unreasonable to expect that input fields are as seen. - not everyone is fully aware of the intricacies of the spec.
Hope that makes sense
Also one more point I'd like to add based on the video above.
Bruno decodes from the url into the param fields (+ in url becomes in param field)
But doesn't encode the other way around (param field is not encoded into the url)
Hence inconsistent behaviour :)
Following up to https://github.com/usebruno/bruno/issues/3187#issuecomment-2473690689, the script should split only the first occurrence of the = in the event you have parameters like &filter=id=1234.
const [url,params] = req.url.split('?');
if(!params) return;
const encodedParams = params.split('&').map((kv) => {
const [k,...vs] = kv.split('=');
const v = vs.join("=")
return `${k}=${encodeURIComponent(v)}`;
}).join('&');
req.setUrl(`${url}?${encodedParams}`);
Previously this message contained a wrong optimization. Please ignore this for future reference
Good point! Here's a slightly more optimized, split can set a limit
Limit works differently than you'd expect (unless you're coming from Java?)
[k,v] = "filter=a=1 and b=2".split('=', 2);
will result in a k = "filter" and v = a
Good point! Here's a slightly more optimized, split can set a limit
Limit works differently than you'd expect (unless you're coming from Java?)
[k,v] = "filter=a=1 and b=2".split('=', 2);will result in a
k="filter"andv=a
Damn you're right. Scratch my previous suggestion!
ran into the same issue. its sad that the features hasn't been added yet :(
This issue has been resolved by #5089 and is available starting from v2.8.0.
URL encoding is no longer visibly applied in the UI — both the Params table and the Request URL field now display values exactly as entered by the user. Bruno will continue to send encoded values to the API server (unless URL encoding is explicitly disabled in the Settings tab for each request).
🔧 Note: URL encoding is enabled by default for newly created requests. However, for backward compatibility, requests from older collections will require manual enabling of this setting if needed.
Closing this issue now. Feel free to reopen it if you continue to experience the problem.