RTSP 400 Bad Request Fix: DESCRIBE Failed, Malformed Camera URL, and Header Errors
Fix RTSP 400 Bad Request on DESCRIBE. Covers malformed camera URLs for Axis/Dahua/Hikvision, unsupported headers, reverse proxy issues, auth, and vendor-specific stream paths with real diagnostic commands.
RTSP/1.0 400 Bad Request means the camera rejected your RTSP request as malformed. It's not a network problem. It's not a codec problem. It's a request-format problem — and it's fixable once you see the exact request the camera received.
Fast answer: 30-second triage
- Test with VLC first. If VLC works, capture the exact RTSP request it sends. Compare to your failing client.
- Check the URL path. Different cameras use completely different paths for the same RTSP stream. Copying a URL from one camera brand to another is the #1 cause of 400 errors.
- Check URL encoding. Special characters in passwords break RTSP URL parsing. Encode
@as%40,:as%3A,/as%2F. - Check for proxy interference. Direct RTSP to the camera works but through a proxy returns 400? The proxy is altering RTSP headers.
If none of these fix it, work through the detailed sections below.
First: verify the camera is reachable
Before debugging RTSP, confirm basic connectivity:
# TCP reachability
nc -zv 192.168.1.100 554
# Or with telnet
telnet 192.168.1.100 554
# RTSP OPTIONS — the simplest RTSP request
# If this fails, the camera isn't speaking RTSP
If the port is closed, the problem is network/firewall, not RTSP.
Camera-specific URL formats
The most common cause of 400 errors: using the wrong URL path format for your camera brand. Each manufacturer uses different conventions:
Axis
rtsp://<ip>/axis-media/media.amp
rtsp://<ip>/mpeg4/media.amp
rtsp://<ip>:554/axis-media/media.amp?videocodec=h264
Dahua
rtsp://<user>:<pass>@<ip>:554/cam/realmonitor?channel=1&subtype=0
rtsp://<user>:<pass>@<ip>:554/cam/realmonitor?channel=1&subtype=1
- subtype=0: main stream
- subtype=1: sub stream
Hikvision
rtsp://<user>:<pass>@<ip>:554/Streaming/Channels/101
rtsp://<user>:<pass>@<ip>:554/Streaming/Channels/102
- 101: channel 1, main stream
- 102: channel 1, sub stream
- 201: channel 2, main stream
Generic / ONVIF
rtsp://<ip>:554/stream1
rtsp://<ip>:554/live
rtsp://<ip>:554/h264
rtsp://<ip>:554/h265
rtsp://<ip>:554/profile1/media.smp
rtsp://<ip>/onvif1
rtsp://<ip>/onvif2
Testing with ffmpeg
# Test DESCRIBE only (don't decode)
ffmpeg -rtsp_transport tcp -i "rtsp://user:pass@192.168.1.100:554/stream1" -t 1 -f null -
# Verbose output shows the exact RTSP exchange
ffmpeg -loglevel debug -rtsp_transport tcp -i "rtsp://..." -t 1 -f null - 2>&1 | grep -E "DESCRIBE|SETUP|response"
URL encoding: the silent 400 trigger
When a password contains special characters, the RTSP URL becomes ambiguous. The @ separates credentials from the host, so a password containing @ breaks the parsing.
WRONG: rtsp://admin:pa@ss@192.168.1.100/stream1
parser sees: user=admin, pass=pa, host=ss@192.168.1.100
RIGHT: rtsp://admin:pa%40ss@192.168.1.100/stream1
parser sees: user=admin, pass=pa@ss, host=192.168.1.100
Characters that must be encoded in RTSP URLs:
| Character | Encoding | Example |
|---|---|---|
@ |
%40 |
user@domain → user%40domain |
: |
%3A |
pass:word → pass%3Aword |
/ |
%2F |
pass/word → pass%2Fword |
? |
%3F |
in query values |
# |
%23 |
in query values |
% |
%25 |
literal percent |
& |
%26 |
in query values (if not separating parameters) |
| space | %20 |
in query values |
Config files often add another layer of escaping. A URL in a YAML file may need both YAML escaping AND URL encoding.
Full diagnostic decision tree
RTSP returns 400 Bad Request
│
├─ Is port 554 reachable?
│ ├─ NO → Fix network/firewall. Not an RTSP issue.
│ └─ YES → Continue
│
├─ Does VLC play the same URL?
│ ├─ YES, VLC works → Capture VLC's exact request. Compare with your client.
│ │ Differences in headers, URI format, or auth will point to the fix.
│ └─ NO, VLC also fails → Problem is in the URL or camera config
│
├─ Check the URL path
│ ├─ Wrong manufacturer format → Use correct format for your camera brand
│ ├─ Query parameters missing → Add required parameters (channel, subtype)
│ └─ Path contains unencoded special chars → URL-encode credentials
│
├─ Check DESCRIBE headers
│ ├─ Missing Accept: application/sdp → Add it
│ ├─ Extra HTTP headers (via proxy) → Remove proxy from RTSP path
│ └─ Malformed Authorization → Fix Digest auth parameters
│
├─ Check CSeq and RTSP syntax
│ ├─ Missing CSeq → Add sequential CSeq header
│ ├─ Wrong RTSP version → Use RTSP/1.0
│ └─ CRLF formatting wrong → Ensure \r\n line endings
│
└─ Still failing?
├─ Try ONVIF discovery to get the correct RTSP URL
├─ Check camera firmware version (older firmware may have stricter parsing)
└─ Test with a known-working RTSP client as baseline
Reverse proxy: the hidden 400 cause
RTSP through an HTTP reverse proxy is fragile. Proxies designed for HTTP may:
- Inject HTTP-specific headers (Host, X-Forwarded-For, User-Agent)
- Rewrite the request URI
- Buffer and alter the TCP connection behavior
- Interfere with RTSP's persistent connection model
Symptoms of proxy interference:
- Direct RTSP to camera: works
- RTSP through proxy: 400 Bad Request
- Camera logs show "malformed request" with extra headers not present in the direct flow
Fix: Either bypass the proxy for RTSP traffic, use an RTSP-aware proxy, or configure the proxy to pass RTSP traffic unmodified.
Authentication edge cases
Most auth problems return 401, but a malformed Authorization header can return 400.
The "works on first try, fails on retry" pattern:
- Client sends unauthenticated DESCRIBE
- Camera returns 401 with Digest challenge (realm, nonce)
- Client computes Digest response
- Client sends authenticated DESCRIBE with Authorization header
- Camera returns 400
This happens when the Digest response computation is wrong — the URI used in the Digest calculation doesn't match the actual request URI, or the nonce was stale, or special characters in the password weren't encoded correctly before hashing.
Check: Compare the request URI in the Authorization header with the actual request URI on the wire. In Digest auth, the URI is part of the hash — if they don't match character-for-character (including encoding), the response is invalid.
When the camera is just broken
Some cameras have buggy RTSP implementations. If you've checked everything above and still get 400:
- Check for firmware updates
- Test with the manufacturer's own client software
- Try ONVIF as an alternative discovery and streaming path
- If the camera works with its own app but not with standards-compliant RTSP clients, the camera's RTSP stack is non-compliant
File a bug with the camera vendor. Include the exact RTSP DESCRIBE request and response. A proper RTSP implementation should not return 400 for a valid, well-formed request regardless of the URL path — it should return 404.
Compare requests without exposing credentials
The fastest RTSP 400 diagnosis is a side-by-side transcript of one known-good request and one failing request. Redact userinfo and Digest response values, but retain request line, URI path/query, CSeq, Accept, Authorization scheme fields, transport-independent headers, line endings, and status. A camera can reject a URI that looks visually identical when percent encoding or the Digest URI differs byte-for-byte.
| Difference on the wire | Why a camera may return 400 | Safe next action |
|---|---|---|
| Request URI lacks required channel/profile query | Vendor parser cannot select a stream | Obtain exact model/NVR path from documented discovery |
| Reserved character unescaped in userinfo/path | Parser splits host, path, or query incorrectly | Encode only the relevant URI component |
CSeq absent/non-numeric |
RTSP request is structurally incomplete | Send a valid sequential CSeq |
Accept: application/sdp missing on DESCRIBE |
Strict server rejects unsupported request shape | Compare a working client's header set |
| Digest URI differs from request URI | Auth retry cannot validate its hash | Keep encoded URI identical in both places |
| Proxy adds/reorders incompatible text | RTSP service receives a modified request | Bypass or configure an RTSP-aware hop |
Do not put real credentials in a support ticket or PCAP export. Preserve a private original for authorized owners and share a redacted request that retains escaping and header structure. The RTSP Inspector connection guide gives the surrounding session context, while the troubleshooting guide helps retain the minimum useful evidence.
Treat 400, 401, 404, and 500 as different branches
Status codes are clues, not interchangeable camera messages. A client can get 401 before it sends a malformed authenticated retry; a bad path may return 404 on one device and an unhelpful 500 on another. Find the first response for the exact request rather than changing every URL setting at once.
| Status after request | What it commonly bounds | Do not conclude |
|---|---|---|
| 400 Bad Request | Parser/header/URI syntax rejected | That the network or codec is broken |
| 401 Unauthorized | Challenge or credentials are required | That an authenticated retry will use the same URI correctly |
| 404 Not Found | Resource/path was not found by that server | That all vendor URL formats are invalid |
| 500 Internal Server Error | Server attempted handling and failed internally | That the request is necessarily malformed |
For server-side resource failures, see RTSP 500 Internal Server Error camera diagnostics. If a correct request connects but never delivers media, move to RTSP connects but no video instead of changing DESCRIBE headers.
FAQ: RTSP DESCRIBE 400 Bad Request
Can a working VLC test prove my application's URL is correct?
It proves a useful baseline, not identity. Compare VLC's actual RTSP request, transport choice, and authenticated retry with the application's request; configuration sources often escape or encode a URL differently.
Should credentials be URL-encoded before Digest authentication?
Encode credentials where they appear in the URL and use the URI form required by the client/server when calculating Digest. Do not blindly encode the entire URL or alter the request target after the Digest value is built.
Does adding HTTP proxy headers help RTSP?
Usually no. HTTP-oriented proxies can change the request shape or persistent connection behavior. Use a path that preserves RTSP semantics.
A good vendor escalation
Include camera/NVR model and firmware, redacted URI pattern, direct versus proxy result, failing and working request-line/header comparison, method/status/CSeq timeline, exact point of the auth retry, and whether the same issue occurs on LAN. Open RTSP Inspector with the limited case export. The desired conclusion is precise: “The authenticated DESCRIBE uses an unencoded @ in userinfo and receives 400; the same path with encoded userinfo reaches the 401/SDP branch.”
How do you validate an RTSP 400 correction?
Capture the complete failing request line and headers with credentials redacted, preserving method,
request-target form, scheme/host/port/path/query, percent-encoding, CSeq, User-Agent,
Accept, Authorization scheme, line endings where visible, and proxy/relay path. Compare it with
one working request against the same camera profile and firmware.
| Request element | What to compare | Common boundary |
|---|---|---|
| URI path/query | Exact bytes and percent-encoding | Reserved character, stale path, wrong channel/profile |
| Host/port/scheme | Direct versus NVR/proxy endpoint | Request sent to a different service |
| Authentication retry | Method and URI used for Digest | Hash built for a request target that later changed |
| Headers | Required/vendor-specific fields and syntax | Malformed or unsupported request shape |
| Framing | CRLF and header termination | Custom client emits invalid RTSP message |
Create a minimal A/B test that changes one URI or header element. Do not normalize the working request after capture; the byte-level difference may be the evidence. A later 401 is progress from syntax into authentication, not proof that credentials are wrong. A later 404 means the server parsed the request but did not resolve that resource.
Test the full session after DESCRIBE
Acceptance is not merely “400 disappeared.” A clean connection should advance through the expected 401/authenticated retry where required, return SDP, resolve media control URLs, SETUP required tracks, PLAY, and receive the expected media. Repeat with the same sanitized URL construction in the actual application so a manual tool does not hide its encoder bug.
Retain failing and corrected request bytes in the RTSP Inspector report workflow and use RTSP 401/404 URL diagnostics after the parser advances to those more specific status boundaries.
Questions about RTSP 400
Can a browser-tested URL prove the RTSP request is valid?
No. Browser URL handling, HTTP proxies, encoding, and authentication differ. Preserve the exact RTSP request target produced by the failing client.
Should the entire URL be percent-encoded?
No. Encode components according to URI rules and the camera/client contract. Encoding separators
such as :, /, ?, or = indiscriminately can create a different path. Keep userinfo secrets
out of shared evidence while retaining the sanitized structure.
Build URI-construction regression cases
Create fixtures for a plain path, spaces or non-ASCII characters where supported, reserved characters in userinfo, query parameters, IPv6 literals, non-default ports, and a URI returned by ONVIF or the vendor. For each fixture, retain the input components, constructed request target, Digest URI input when used, and server status. Never place real credentials in the fixture.
Test that redirects or proxy rewriting do not silently switch from RTSP semantics to HTTP request forms. If a proxy is required, preserve the request on both sides and name which component changed the path or headers.
Add the corrected case to the client’s regression suite and assert the exact request-target bytes, not only “status is no longer 400.” A server firmware change can begin accepting malformed input while another camera still rejects it. The durable fix is a standards- and vendor-contract-aware URI builder whose output, authentication calculation, and subsequent track URLs remain consistent through a complete RTSP session.
Retain the tested client and camera firmware versions with that regression evidence.
<!-- multilingual-related-reading:start -->Related guides
Continue with the same-language pages below. They cover adjacent stages without changing the canonical owner of this topic:
<!-- multilingual-related-reading:end -->