Error reference HTTP status

How to fix a 400 Bad Request error

A 400 Bad Request is the server telling you it read your request and couldn't make sense of it — malformed URL encoding, oversized cookie headers, a body that doesn't match its Content-Type, or the wrong protocol spoken on the wrong port. It's deterministic: the same broken request fails every time. Here's how to find the malformed piece and fix it.

400 Bad Request

What 400 Bad Request means

HTTP 400 is the server's generic rejection for a request it parsed and found invalid. Unlike 401 or 403, it says nothing about who you are — it says the bytes you sent don't form a request the server is willing to process. The spec definition covers malformed syntax, invalid framing, and deceptive routing, which in practice means a handful of recurring culprits.

The most common triggers: unencoded characters in the URL (spaces, quotes, non-ASCII), oversized or corrupted Cookie headers (many servers cap total header size around 8 KB), a request body that contradicts its Content-Type or Content-Length, invalid characters in header values, and protocol mismatches — the classic being nginx's 'The plain HTTP request was sent to HTTPS port'.

Two properties make 400s easy to debug once you know them: they're deterministic (the identical request fails every time, so blind retries are pointless), and they can be issued by any hop that parses HTTP — the target server, a load balancer in front of it, or the proxy you're routing through. Your job is to find which hop rejected you and what it choked on.

400 Bad Request

How to fix 400 Bad Request, step by step

Work through these in order — they're sorted by how often each one is the actual cause in scraping and API pipelines.

  1. URL-encode everything you put in the URL. Spaces, quotes, brackets, and non-ASCII characters must be percent-encoded. Let your HTTP client build the query string (params={...} in Python requests) instead of concatenating strings.
  2. Clear your cookies and retry with a fresh session. Long-lived sessions accumulate Set-Cookie data until the request tops the server's header-size limit — the telltale variant is 'Request Header Or Cookie Too Large'.
  3. Validate your headers. No newlines or control characters in values, a correct Host header, and no hand-set Content-Length — let the client compute it.
  4. Match the body to the Content-Type. Sending form-encoded data with application/json (or invalid JSON with it) is a top-three cause of API 400s. Validate the payload before sending.
  5. Check the scheme and port. Plain HTTP sent to an HTTPS port returns an immediate 400 on nginx-based stacks; https:// URLs must be requested as HTTPS.
  6. Reproduce with curl -v to see exactly what goes on the wire — the verbose output shows the request line, every header, and which hop answered.
  7. Diff against a working browser request. Use DevTools' Copy as cURL on the same URL and compare headers one by one; the difference is usually the bug.
400 Bad Request

Where proxy configuration causes 400s

A proxy is an extra hop that must also parse your request, which adds one new class of 400: protocol mismatch on the proxy port. If your client speaks TLS to a listener expecting plain HTTP proxy syntax, or sends SOCKS bytes to an HTTP endpoint, the listener sees bytes it can't parse and rejects them — sometimes as a 400, sometimes as a dropped connection.

ProxyOmega removes most of this class by design: every port — including the standard residential.proxyomega.com:10000 entry point — accepts HTTP, HTTPS, and SOCKS5 on the same port, so there is no wrong-port variant of the mismatch. What remains is client-side configuration: the proxy URL scheme in your code still has to match the protocol your library will actually speak.

Wrong proxy scheme in your client

In most HTTP libraries the proxy URL should be http:// even for HTTPS traffic — the client opens a tunnel through the proxy and runs TLS end to end inside it. Writing https:// as the proxy scheme makes some clients attempt TLS against the proxy listener itself, which fails or produces malformed bytes.

Use http://user:[email protected]:10000 for both http and https traffic, or socks5:// if you prefer SOCKS — same host, same port.

Cookie and header bloat in long-running scrapers

Reused session objects hoard cookies from every domain they touch. After a few thousand requests, the Cookie header alone can exceed a server's header budget and everything starts returning 400. Cycle sessions periodically, or scope one session per target domain.

If you also need IP continuity while a session lives, pin it with ProxyOmega's -session-<id> username parameter instead of holding one global client object forever.

Hand-built requests and absolute-form URLs

Proxy-style HTTP puts an absolute URI in the request line (GET http://example.com/path), while origin servers expect the relative form (GET /path). Scripts that build raw requests by hand and reuse them with and without a proxy get 400s from strict servers.

Use a real HTTP client — requests, httpx, curl — and let it format the request line correctly for each hop.

400 Bad Request

Sending a well-formed request through a proxy

This request avoids every failure mode above: the library percent-encodes the query, computes Content-Length, sends a clean header set, and tunnels HTTPS through the proxy with the correct http:// proxy scheme.

import requests

# Same port serves HTTP, HTTPS, and SOCKS5
proxy = "http://USERNAME:[email protected]:10000"
proxies = {"http": proxy, "https": proxy}

params = {"q": "wireless headphones", "page": 1}   # percent-encoded for you
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0 Safari/537.36",
    "Accept": "application/json",
}

r = requests.get(
    "https://api.example.com/search",
    params=params,
    headers=headers,
    proxies=proxies,
    timeout=30,
)
r.raise_for_status()
print(r.status_code, len(r.content))
FAQ

Frequently asked questions

Is a 400 Bad Request my fault or the server's?
Almost always the request. A 400 is the parse-and-reject class: the server read your bytes and refused them, so the same request will fail deterministically until something in it changes. Occasionally an aggressive WAF returns 400 instead of 403 for filtered traffic, but start by validating your URL encoding, headers, and body — that's the cause in the large majority of cases.
Can a proxy cause a 400 error?
Yes, in one specific way: a protocol mismatch where your client speaks the wrong protocol to the proxy port, producing bytes the listener can't parse. ProxyOmega reduces this surface because every port accepts HTTP, HTTPS, and SOCKS5 — but the proxy URL scheme in your code still has to match what your library actually sends. Everything else about a 400 is usually the request itself.
Why does the URL work in my browser but return 400 in my script?
Browsers silently fix what scripts don't: they percent-encode URLs, manage cookie size, and send a complete, consistent header set. Your script is probably sending an unencoded character, a stale cookie jar, or a contradictory header. Use DevTools' Copy as cURL on the working browser request and diff it against your script's request — the mismatch is the answer.
Does rotating proxy IPs help with 400 errors?
No. A 400 is about request formatting, not sender reputation, so a new IP resends the same broken bytes and gets the same rejection. Rotation is the right tool for 403s and 429s, where the server objects to who is asking rather than what is being asked. Fix the request first, then think about IP strategy.

Fix the request once, then scale it. Start routing today.

ProxyOmega serves HTTP, HTTPS, and SOCKS5 on every port — 90M+ IPs across 200+ countries behind one endpoint.

ProxyOmega ProxyOmega

90M+ ethically-sourced IPs across 200+ countries and 30,000+ cities. Residential, mobile, ISP and IPv6 proxies for scraping and AI agents.

GDPRCCPA
Product
Premium Unlimited Budget Unlimited Residential / ISP Mobile IPv6 Chrome Extension
Solutions
Web scraping AI agents Price monitoring SERP & SEO Integrations All use cases
Resources
Glossary Error codes Free tools Proxies by platform Locations
Company
About Blog Docs Reseller program Affiliate Contact Sign in
© 2026 ProxyOmega Ltd. All rights reserved.