Skip to content
Back to skills

Http Error Triage

ASecurity

Run before concluding anything from an HTTP error on a third-party API. Separates a real credential/entitlement problem from a CDN or WAF block, a wrong endpoint, or a client-signature ban. Use whenever an API returns 401/403/402/429 and you are about to say "the key is dead", "credits are exhausted", "the plan lacks access", or "we are rate limited".

  • 3 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added September 19, 2026
ai-agentspythongoapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned September 19, 2026

npx -y skills add getedgehq/skills --skill http-error-triage --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Http Error Triage?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Http Error Triage
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/getedgehq-http-error-triage/badge)](https://www.skillsdirectory.com/skills/getedgehq-http-error-triage)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: http-error-triage
description: Run before concluding anything from an HTTP error on a third-party API. Separates a real credential/entitlement problem from a CDN or WAF block, a wrong endpoint, or a client-signature ban. Use whenever an API returns 401/403/402/429 and you are about to say "the key is dead", "credits are exhausted", "the plan lacks access", or "we are rate limited".
---

# HTTP error triage

An HTTP error tells you a request failed. It usually does **not** tell you why.
Concluding "the key is dead" from a 403 is a guess wearing a number.

Born from a real incident (2026-07-30): a third-party contact-enrichment API
returned `403 error code: 1010` to every call for six days. It was read as "key
not entitled", "credits exhausted", "monthly quota reached". A 756-line browser
automation workaround was built on that belief, and a customer was nearly asked
to check a plan that was fine. The actual cause was a missing `User-Agent`, so
the CDN banned the client at the edge. One header fixed it: 200 OK, full data,
and the credit balance had been there the whole time.

## Run these three controls before you diagnose

**1. The invalid-credential control.** Send the same request with a deliberately
garbage credential, and again with none at all.

```python
for label, key in [("real", REAL_KEY), ("garbage", "0"*36), ("empty", "")]:
    ...  # same URL, same method, same headers
```

If all three return the **same** status and body, the error is not about your
credential. It carries zero information about entitlement, quota or validity.
Stop reasoning about the key.

**2. The nonsense-path control.** Request a path that certainly does not exist,
and the site root.

```
GET https://api.example.com/definitely-not-a-real-path-12345
GET https://api.example.com/
GET https://www.example.com/          # their marketing site
```

If the API error also comes back from the marketing site, you are being blocked
**in front of** the origin. Nothing about the API call will help.

**3. Read the response headers, not just the body.**

```python
except urllib.error.HTTPError as e:
    print(e.code, e.headers.get("server"), e.read()[:200])
```

`server: cloudflare` on an "auth" error is the giveaway. So are `cf-ray`,
`x-amzn-waf`, `akamai`. Those are infrastructure, not the API.

## Known signatures

| Symptom | Real cause | Fix |
|---|---|---|
| `403` + body `error code: 1010`, `server: cloudflare` | Cloudflare banned the client signature | Send a real browser `User-Agent` |
| Same error for every path incl. `/` | Edge/WAF block or IP ban | Change UA, then IP/proxy |
| `402` | Genuinely out of credits: the request **authenticated** | Top up; the key is fine |
| `429` right after a success | Real rate limit | Pace requests, add backoff |
| `400` with a field message | You reached the API and auth passed | Fix the payload; this is good news |

A `400` validation error is a **success signal** for triage: it proves auth was
accepted.

## Default headers for any server-side API call

Python's `urllib` sends `User-Agent: Python-urllib/3.x`, which many WAFs ban
outright. Always set:

```python
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36",
    "Accept": "application/json",
    "Content-Type": "application/json",
}
```

## Then measure cost before any sweep

Once it works, do not estimate spend. Read usage before and after one call, and
read the provider's own billing field in the response.

```python
before = usage(); result = call(); after = usage()
print("charged:", result.get("billing"), "| measured:", before - after)
```

## What to report

State what you tested and what remains unknown. "Both keys 403" is not a finding
if an empty key returns the same 403. Say instead: "403 is uninformative here, a
null credential returns it too; the cause is upstream of auth."

Files in this skill

  • DERIVATION.json2.8 KB
  • LICENSE10.5 KB
  • SKILL.md3.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.