agentleFS
getedgehqgetedgehq/skills/http-error-triage/SKILL.md

http-error-triage

Skill5 starsChanged 11 days agoApache-2.0View on GitHub

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

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If all three return the same status and body, the error is not about your credential.

    line 29
  2. Distinctive:

    Stop reasoning about the key.

    line 31
  3. Distinctive:

    If the API error also comes back from the marketing site, you are being blocked

    line 42

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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.

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.

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

SymptomReal causeFix
403 + body error code: 1010, server: cloudflareCloudflare banned the client signatureSend a real browser User-Agent
Same error for every path incl. /Edge/WAF block or IP banChange UA, then IP/proxy
402Genuinely out of credits: the request authenticatedTop up; the key is fine
429 right after a successReal rate limitPace requests, add backoff
400 with a field messageYou reached the API and auth passedFix 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:

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.

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

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.