Fix: HTTPie Not Working — JSON Body, Authentication, and Session Errors
Quick Answer
How to fix HTTPie errors — installation collision with httpie-cli, JSON body interpretation, multipart form data, OAuth bearer token, persistent sessions, SSL verification skip, and download mode.
The Error
You install HTTPie and run a basic request — it fails to parse JSON correctly:
$ http POST httpbin.org/post name=Alice age=30
# Sent as form data, not JSON
# Body: "name=Alice&age=30"Or sending an integer becomes a string:
$ http POST httpbin.org/post age:=30 active:=true
# Should be: {"age": 30, "active": true}
# Common mistake: omitting := for typed valuesOr session-based auth doesn’t persist:
$ http --auth user:pass GET httpbin.org/basic-auth/user/pass
# OK
$ http GET httpbin.org/get
# Auth not preserved — new session each timeOr HTTPS requests fail behind a corporate proxy:
$ https example.com
SSLError: certificate verify failed: unable to get local issuer certificateOr the http command isn’t found after install:
$ pip install httpie
$ http GET httpbin.org/get
bash: http: command not foundHTTPie is the modern alternative to curl — colorized output, JSON-aware syntax, intuitive headers/parameters. Used heavily for API exploration and quick HTTP debugging. The shorthand syntax (field=value vs field:=value vs field==value) is concise but confuses newcomers — = for strings, := for raw JSON values, == for query parameters. This guide covers each common issue.
Why This Happens
HTTPie’s syntax is designed for terseness — three different separators for three different parameter types. The conciseness saves typing but the rules aren’t immediately obvious. Sessions, authentication, and SSL verification follow standard patterns but the CLI flags differ from curl’s.
Fix 1: Installation and PATH
# Recommended — install via pipx for global isolated CLI
pipx install httpie
# Or pip
pip install --user httpie
# Or uv
uv tool install httpie
# Or platform package managers
brew install httpie # macOS
apt install httpie # Debian/Ubuntu
choco install httpie # Windows ChocolateyVerify install:
http --version
# 3.2.4
which http
# /usr/local/bin/http or ~/.local/bin/httpCommon Mistake: Installing via pip install httpie-cli instead of httpie. The package name is httpie — there’s no httpie-cli on PyPI. The error is “package not found.” Search PyPI for the correct name (the project’s homepage at httpie.io shows the exact install command).
Modern HTTPie also installs https for HTTPS shortcuts:
http GET example.com # http://example.com
https GET example.com # https://example.com — same as http -sFor broader Python packaging issues that affect HTTPie install, see Python packaging not working.
Fix 2: Request Syntax — =, :=, ==, :
The four separators each mean something different:
| Separator | Use | Example | Sends |
|---|---|---|---|
= | JSON field (string) | name=Alice | {"name": "Alice"} |
:= | JSON field (raw) | age:=30 | {"age": 30} |
== | URL query parameter | q==search | ?q=search |
: | HTTP header | X-Token:abc | Header X-Token: abc |
@ | File upload (multipart) | [email protected] | Form field with file |
Examples:
# POST JSON: {"name": "Alice", "age": 30, "active": true}
http POST httpbin.org/post \
name=Alice \
age:=30 \
active:=true
# Query parameters: GET /search?q=foo&limit=10
http GET httpbin.org/get q==foo limit==10
# Headers
http GET httpbin.org/get \
X-API-Key:secret \
Accept:application/json
# Combined
http POST api.example.com/users \
Authorization:"Bearer token" \
User-Agent:my-client \
name=Alice \
age:=30Common Mistake: Sending age=30 (string) when you mean age:=30 (integer). The endpoint sees "age": "30" instead of "age": 30 — fails server-side validation that expects an integer. Always use := for non-string types (numbers, booleans, arrays, objects).
Pro Tip: For complex JSON values, use := with explicit JSON:
http POST api.example.com/users \
name=Alice \
tags:='["admin", "active"]' \
address:='{"city": "NYC", "zip": "10001"}'The single quotes around the JSON keep the shell from interpreting it.
Fix 3: Sending Form Data
For application/x-www-form-urlencoded or multipart/form-data instead of JSON:
# Form-encoded — use --form (or -f)
http --form POST httpbin.org/post name=Alice age=30
# Body: "name=Alice&age=30"
# Content-Type: application/x-www-form-urlencoded
# Multipart — automatic when using file uploads with @
http POST httpbin.org/post \
--form \
name=Alice \
[email protected]
# Content-Type: multipart/form-dataFile upload as JSON body:
# Read file contents into a JSON field
http POST api.example.com/upload \
name=Alice \
data:[email protected] # := and @ — include the JSON file content as a value
# Read entire body from file
http POST api.example.com/upload @body.jsonFix 4: Authentication
# Basic auth
http --auth user:pass GET httpbin.org/basic-auth/user/pass
# Bearer token via header
http GET api.example.com/me Authorization:"Bearer eyJ..."
# Or use --auth-type
http --auth-type bearer --auth eyJ... GET api.example.com/me
# Digest auth
http --auth-type digest --auth user:pass GET httpbin.org/digest-auth/auth/user/pass
# Custom token formats
http GET api.example.com/me X-API-Key:my-secret-keyPlugin auth types (OAuth, AWS Sig, JWT):
# OAuth
pip install httpie-oauth
http --auth-type=oauth1 --auth='client_id:client_secret' GET api.example.com/
# AWS Sig
pip install httpie-aws-auth
http --auth-type=aws4 --auth='AKID:SECRET' GET https://my-bucket.s3.amazonaws.com/Pro Tip: For repeated requests with the same auth, use sessions (covered in next fix). Typing --auth user:pass for every request to your dev API gets old fast.
Fix 5: Persistent Sessions
# Create or use a session named "my-api"
http --session=my-api --auth user:pass GET api.example.com/me
# Subsequent requests in the same session reuse cookies and auth
http --session=my-api GET api.example.com/data
# Auth header automatically included from sessionSessions store:
- Cookies (persist across requests)
- Auth credentials
- Custom headers added with
--header
Session storage — ~/.config/httpie/sessions/<host>/<name>.json:
ls ~/.config/httpie/sessions/api.example.com/
# my-api.json
cat ~/.config/httpie/sessions/api.example.com/my-api.json
# {
# "auth": {"type": "basic", "raw_auth": "user:pass"},
# "cookies": [...],
# "headers": {...}
# }Anonymous sessions for cookies only:
http --session=./local-session.json POST api.example.com/login user=alice password=secret
# Cookies stored in ./local-session.json (instead of global config)
http --session=./local-session.json GET api.example.com/profile
# Cookies sent automaticallyRelative path stores the session as a file you can commit/share/version (useful for shared dev environments).
Common Mistake: Forgetting that sessions are PER-HOST. A session named my-api for api.example.com doesn’t carry over to api.test.com — different host, different storage.
Fix 6: SSL Certificate Issues
# Skip SSL verification (development ONLY)
http --verify=no GET https://self-signed.example.com
# Custom CA bundle (corporate proxies, internal CAs)
http --verify=/path/to/corporate-ca.pem GET https://internal.example.com
# Client certificates (mutual TLS)
http --cert=client.pem --cert-key=client-key.pem GET https://api.example.comCommon error in corporate networks:
SSLError: certificate verify failed: unable to get local issuer certificateCorporate firewalls often intercept HTTPS with their own CA. Either:
- Get the corporate CA bundle from IT, use
--verify=/path/to/bundle.pem - Set
REQUESTS_CA_BUNDLEenv var (HTTPie respects it):
export REQUESTS_CA_BUNDLE=/path/to/corporate-ca.pem
http GET https://internal.example.comNever use --verify=no in scripts — it disables MITM protection. Only for one-off debugging.
For Python requests SSL patterns that also apply to HTTPie, see Python SSL certificate verify failed.
Fix 7: Output Formatting and Download Mode
# Suppress request output, show only response
http GET httpbin.org/get
# Show only response body (no headers)
http -b GET httpbin.org/get
# Show only headers (no body)
http -h GET httpbin.org/get
# Show everything (request + response, headers + body) — useful for debugging
http -v GET httpbin.org/get
# Download mode (saves response to file)
http --download GET https://example.com/file.zip
# Auto-detects filename from Content-Disposition or URL
# Saves to ./file.zip
# Custom output filename
http --download --output ./downloaded.zip GET https://example.com/file.zip
# Resume interrupted download
http --download --continue GET https://example.com/huge-file.zipPretty-print JSON response:
http GET api.example.com/users
# Colorized, indented JSON by default
# Disable colors (for piping/scripting)
http --pretty=none GET api.example.com/users
http --pretty=format GET api.example.com/users # Format but no colorsCommon Mistake: Piping HTTPie output to a file and getting ANSI color codes. Use --pretty=none or --pretty=format when redirecting:
# WRONG — file contains color codes
http GET api.example.com/users > users.json
# CORRECT
http --pretty=none GET api.example.com/users > users.json
# Or just use the body-only mode
http -b GET api.example.com/users > users.jsonFix 8: Proxy and Timeout Configuration
# HTTP proxy
http --proxy=http:http://proxy.example.com:8080 GET httpbin.org/ip
# HTTPS proxy
http --proxy=https:http://proxy.example.com:8080 GET https://httpbin.org/ip
# Both via environment variables (HTTPie respects standard vars)
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
http GET httpbin.org/ip
# SOCKS5 proxy (requires httpie[socks])
pip install httpie[socks]
http --proxy=socks5://localhost:1080 GET httpbin.org/ip
# Timeout (seconds)
http --timeout=10 GET httpbin.org/delay/5
# Disable redirects
http --follow=no GET httpbin.org/redirect/3Print effective configuration:
http --debug GET httpbin.org/get
# Shows internal state — useful for debugging "why isn't my flag working?"Still Not Working?
HTTPie vs curl vs xh
- HTTPie — Human-friendly, colorized, JSON-aware. Best for interactive API exploration.
- curl — Universal, scriptable, available everywhere. Best for scripts and CI.
- xh — Rust-based clone of HTTPie, much faster startup. Best when you use HTTPie heavily and notice the Python startup time.
For exploring APIs interactively, HTTPie wins. For shell scripts running thousands of requests, xh (or curl) reduces overhead. HTTPie 4.0+ has improved startup time but still slower than Rust alternatives.
Scripting with HTTPie
# Capture response in shell variable
USERS=$(http -b GET api.example.com/users)
echo "$USERS" | jq '.[]'
# Send POST body from variable
DATA='{"name": "Alice"}'
http POST api.example.com/users <<<"$DATA"
# Iterate over IDs
for id in 1 2 3; do
http -b GET api.example.com/users/$id
done
# Save status code
STATUS=$(http -h GET api.example.com/health | head -1 | awk '{print $2}')
if [ "$STATUS" = "200" ]; then
echo "OK"
fiFor shell automation patterns, HTTPie pairs cleanly with jq for JSON manipulation.
Custom Headers File
For complex header sets, use a session or a wrapper script:
# ~/.bashrc
function api() {
http --session=my-api "$@"
}
# Now any HTTPie command via `api` reuses the session
api GET httpbin.org/getHTTPie in CI
# .github/workflows/test.yml
- name: Smoke test API
run: |
pip install httpie
http --check-status GET https://api.example.com/health
# --check-status exits non-zero on 4xx/5xx--check-status makes HTTPie behave like a proper CI tool — exit 1 for HTTP errors, exit 0 for success.
Sending Binary Data
# Upload binary file as body
http POST api.example.com/upload @binary.dat
# Force binary output (don't decode response)
http --raw GET https://example.com/image.png > image.pngFor multipart uploads with binary data, see Fix 3.
Testing GraphQL APIs
http POST api.example.com/graphql \
query='{ users { id name } }'Or send the full GraphQL request:
http POST api.example.com/graphql \
[email protected] \
variables:='{"id": 1}'For testing GraphQL APIs, HTTPie’s terse syntax is significantly nicer than curl’s escape-heavy approach.
Integration with FastAPI / Flask Development
# Quick test of FastAPI dev server
uvicorn main:app --reload &
http GET localhost:8000/users
http POST localhost:8000/users name=Alice age:=30
# With auth
http --session=dev --auth admin:secret POST localhost:8000/login
http --session=dev GET localhost:8000/admin/usersFor FastAPI development patterns, see FastAPI dependency injection error. For Uvicorn dev server setup, see Uvicorn not working.
Plugins Worth Knowing
HTTPie has a plugin ecosystem for auth schemes, transports, and formatters:
# OAuth (1.0 and 2.0)
pip install httpie-oauth
# AWS Sig v4
pip install httpie-aws-auth
# JWT helpers
pip install httpie-jwt-auth
# HTTPie Desktop (GUI version) — works with the same syntax
# Available at httpie.io/desktopInstall plugins in the same Python environment as HTTPie. If installed via pipx, run pipx inject httpie httpie-oauth.
Compared to Python requests
HTTPie wraps the requests library — the same SSL, proxy, and connection-pool behavior. For automating HTTP from Python directly, use requests or httpx. HTTPie is for interactive command-line use; once you need scripting, transitioning to Python code is usually cleaner.
For httpx-specific async patterns, see httpx not working. For Python requests patterns, see Python requests timeout.
Print Curl Equivalent
Useful for sharing requests in documentation:
http --print=H GET httpbin.org/get # Just request headers — quick checkFor converting between HTTPie and curl syntax, several online tools exist; the patterns map cleanly once you know the separator rules.
Reusing Common Headers
For APIs that require the same headers on every request, create a wrapper:
# ~/.bashrc
function myapi() {
http \
--auth-type=bearer \
--auth="$API_TOKEN" \
--session=myapi \
"X-Org-Id:my-org" \
"$@"
}
# Usage
myapi GET api.example.com/users
myapi POST api.example.com/users name=AliceThe function injects auth and headers; remaining args pass through unchanged.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Click Not Working — Group Setup, Context Passing, and Parameter Type Errors
How to fix Click errors — UsageError missing argument, Group has no command, ctx.obj not passing between commands, ParamType validation failed, BadOptionUsage no such option, pass_context required, and lazy loading groups.
Fix: Rich Not Working — Live Display Issues, Color in CI, and Console Configuration
How to fix Rich errors — colors not appearing in CI logs, Live display flickering, progress bar not updating, table column overflow, traceback install conflicts, and Console redirect issues.
Fix: Typer Not Working — Argument Errors, Autocomplete, and Subcommand Issues
How to fix Typer errors — type annotation required error, Optional argument parsing, boolean flag conventions, autocomplete installation failed, nested commands not found, and rich traceback disable.
Fix: Clack Not Working — Prompts Not Displaying, Spinners Stuck, or Cancel Not Handled
How to fix @clack/prompts issues — interactive CLI prompts, spinners, multi-select, confirm dialogs, grouped tasks, cancellation handling, and building CLI tools with beautiful output.