Inconsistent argument parsing behavior across Python versions (< 3.13 vs 3.13+)
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
Research direction
Start in httpie/cli/argparser.py, especially parse_args and its parse_known_args calls around lines 97, 129, and 159. Reproduce the two commands under Python 3.11, 3.12, and 3.13, then compare the parser behavior with the possible parse_intermixed_args approach. Done means the project has a decided solution—consistent parsing or an explicitly documented limitation—validated across the supported Python versions.
Written by the indexing model from the issue text.
Description
Checklist
- I've searched for similar issues.
- I'm using the latest version of HTTPie.
Summary
I discovered that the position of optional flags (like -v) affects argument parsing differently depending on the Python version. This is due to improvements in Python 3.13's argparse module, but it creates an inconsistent user experience for users on Python 3.11/3.12 (which are still officially supported until 2027-2028).
Minimal reproduction code and steps
The position of the -v flag affects argument parsing differently depending on the Python version being used.
Test Case 1: -v flag after URL (fails on Python 3.11-3.12, works on 3.13+)
$ http --offline --ignore-stdin post pie.dev/post -v 'header1:xyz' x=1
Test Case 2: -v flag before URL (fails on all versions tested)
$ http --offline --ignore-stdin post -v pie.dev/post 'header1:xyz' x=1
Current result
Python 3.11 (Version 3.11.15)
$ http --offline --ignore-stdin post pie.dev/post -v 'header1:xyz' x=1
usage:
http [METHOD] URL [REQUEST_ITEM ...]
error:
unrecognized arguments: header1:xyz x=1
for more information:
run 'http --help' or visit https://httpie.io/docs/cli
Python 3.12 (Version 3.12.3)
$ http --offline --ignore-stdin post pie.dev/post -v 'header1:xyz' x=1
usage:
http [METHOD] URL [REQUEST_ITEM ...]
error:
unrecognized arguments: header1:xyz x=1
for more information:
run 'http --help' or visit https://httpie.io/docs/cli
Python 3.13 (Version 3.13.5) or higher
$ http --offline --ignore-stdin post pie.dev/post -v 'header1:xyz' x=1
POST /post HTTP/1.1
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 10
User-Agent: HTTPie/3.2.4
Accept: application/json, */*;q=0.5
Content-Type: application/json
header1: xyz
Host: pie.dev
{"x": "1"}
✅ Works correctly on Python 3.13+
Expected result
Ideally, the command should work consistently across all supported Python versions, regardless of whether optional flags like -v are placed before or after the URL.
While I understand this is caused by Python's argparse improvements in 3.13, I wanted to bring this to your attention because:
- Many users are still on Python 3.11/3.12 (officially supported until 2027-2028)
- This creates a confusing user experience where the same command works differently
- There might be room for improvement through documentation or potential workarounds
Debug output
Python 3.12
$ http --debug --offline --ignore-stdin post pie.dev/post -v 'header1:xyz' x=1
HTTPie 3.2.4
Requests 2.33.1
Pygments 2.20.0
Python 3.12.3 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0]
/home/user/env312/bin/python
Linux 5.15.167.4-microsoft-standard-WSL2
<Environment {...}>
<PluginManager {...}>
usage:
http [METHOD] URL [REQUEST_ITEM ...]
error:
unrecognized arguments: header1:xyz x=1
for more information:
run 'http --help' or visit https://httpie.io/docs/cli
Python 3.13
$ http --debug --offline --ignore-stdin post pie.dev/post -v 'header1:xyz' x=1
HTTPie 3.2.4
Requests 2.33.1
Pygments 2.20.0
Python 3.13.5 (main, Apr 27 2026, 03:43:50) [GCC 9.5.0]
/home/user/env313/bin/python
Linux 5.15.167.4-microsoft-standard-WSL2
<Environment {...}>
<PluginManager {...}>
>>> requests.request(**{'auth': None,
'data': b'{"x": "1"}',
'headers': <HTTPHeadersDict(...)>,
'method': 'post',
'params': <generator object MultiValueOrderedDict.items at 0x...>,
'url': 'http://pie.dev/post'})
POST /post HTTP/1.1
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 10
User-Agent: HTTPie/3.2.4
Accept: application/json, */*;q=0.5
Content-Type: application/json
header1: xyz
Host: pie.dev
{"x": "1"}
Additional information
This issue appears to be caused by changes in Python's argparse.ArgumentParser.parse_known_args() behavior between Python 3.12 and 3.13.
HTTPie uses parse_known_args() in httpie/cli/argparser.py (lines 97, 129, 159) to handle the mix of positional and optional arguments. The Python 3.13 release includes improvements to argparse that better handle intermixed optional and positional arguments.
Code Reference
The parsing happens in httpie/cli/argparser.py:
def parse_args(
self,
env: Environment,
args=None,
namespace=None
) -> argparse.Namespace:
self.env = env
self.args, no_options = self.parse_known_args(args, namespace) # Line 159
# ... rest of the method
Impact
- Users on Python 3.11 and 3.12 (which are still widely used) experience inconsistent behavior
- The position of optional flags shouldn't matter for argument parsing
- This creates confusion for users who might be used to putting flags anywhere in the command
Possible Approaches (open for discussion)
- Documentation: Add a note about this limitation for Python < 3.13 users (recommend placing optional flags before the URL)
- Workaround consideration: Evaluate if using
argparse.ArgumentParser.parse_intermixed_args()would help (available since Python 3.7) - Informational only: Perhaps this is just something to be aware of as Python 3.11/3.12 approach EOL
I'm happy to contribute documentation updates or help test any potential solutions if you think this is worth addressing. I'm also open to this just being "working as intended" given the Python version constraints.
Related
- Python 3.13 What's New: https://docs.python.org/3/whatsnew/3.13.html#argparse
- Python argparse documentation: https://docs.python.org/3/library/argparse.html
- #1828 (parser complexity / mixed responsibilities)
This issue focuses specifically on observable cross-version parsing behavior.
Environment
- HTTPie version: 3.2.4
- Python versions tested: 3.11.15, 3.12.3, 3.13.5, 3.14.4
- OS: Linux (WSL2)
- Requests version: 2.33.1
- Dominant language
- Python
- Stars
- 38.6k
- Forks
- 4k
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from httpie/cli
-
new
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
Difficulty 3/5 1-2 days Newbie friendliness 55/100
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
Similar issues
-
area: harness bug status: needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Human-Agent-Society/reef#625 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 1/5 Under an hour Newbie friendliness 80/100
learningequality/kolibri#15351 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Name consistency Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
eellak/triplestore#65 · 1 comment ·