Skip to content

Fix: HTTPie Not Working — JSON Body, Authentication, and Session Errors

FixDevs ·

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 values

Or 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 time

Or HTTPS requests fail behind a corporate proxy:

$ https example.com
SSLError: certificate verify failed: unable to get local issuer certificate

Or the http command isn’t found after install:

$ pip install httpie
$ http GET httpbin.org/get
bash: http: command not found

HTTPie 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 Chocolatey

Verify install:

http --version
# 3.2.4

which http
# /usr/local/bin/http  or  ~/.local/bin/http

Common 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 -s

For broader Python packaging issues that affect HTTPie install, see Python packaging not working.

Fix 2: Request Syntax — =, :=, ==, :

The four separators each mean something different:

SeparatorUseExampleSends
=JSON field (string)name=Alice{"name": "Alice"}
:=JSON field (raw)age:=30{"age": 30}
==URL query parameterq==search?q=search
:HTTP headerX-Token:abcHeader 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:=30

Common 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-data

File 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.json

Fix 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-key

Plugin 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 session

Sessions 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 automatically

Relative 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.com

Common error in corporate networks:

SSLError: certificate verify failed: unable to get local issuer certificate

Corporate firewalls often intercept HTTPS with their own CA. Either:

  1. Get the corporate CA bundle from IT, use --verify=/path/to/bundle.pem
  2. Set REQUESTS_CA_BUNDLE env var (HTTPie respects it):
export REQUESTS_CA_BUNDLE=/path/to/corporate-ca.pem
http GET https://internal.example.com

Never 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.zip

Pretty-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 colors

Common 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.json

Fix 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/3

Print 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"
fi

For 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/get

HTTPie 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.png

For 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/users

For 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/desktop

Install 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.

Useful for sharing requests in documentation:

http --print=H GET httpbin.org/get   # Just request headers — quick check

For 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=Alice

The function injects auth and headers; remaining args pass through unchanged.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles