Cloudflare purge cache 400 "Invalid request headers" in CI
Cloudflare rejected the request before checking the token: a 400 with code 6003 "Invalid request headers" means a header is malformed, most often mixing bearer-token and legacy X-Auth-Key auth, or sending an empty Authorization value.
What this error means
The purge call returns HTTP 400 with error code 6003 and sub-errors like 6111 "Invalid format for Authorization header". It fails identically on every run.
{
"success": false,
"errors": [
{ "code": 6003, "message": "Invalid request headers",
"error_chain": [
{ "code": 6111, "message": "Invalid format for Authorization header" }
] }
]
}Common causes
Bearer and legacy auth headers are mixed
The request sends both Authorization: Bearer and X-Auth-Key/X-Auth-Email, or a bearer token with the legacy X-Auth-* headers, which Cloudflare rejects as invalid.
The Authorization header is empty or malformed
An unset secret expands to Authorization: Bearer with no value, so the header format is invalid and never reaches token verification.
How to fix it
Use exactly one auth scheme
- For an API token, send only
Authorization: Bearer <token>. - For the legacy key, send only
X-Auth-EmailandX-Auth-Key; do not combine the two. - Confirm the secret is non-empty so the header has a value.
# API token (preferred): one header only
curl -sS -X POST \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'Guard against an empty token
Fail fast if the secret did not populate so the header is never sent empty.
if [ -z "${CF_API_TOKEN}" ]; then
echo "CF_API_TOKEN is empty; check the secret binding"; exit 1
fiHow to prevent it
- Pick one auth scheme (bearer token) and remove legacy X-Auth headers.
- Assert the token secret is non-empty before building the header.
- Always set Content-Type: application/json on the purge request.