online / endpoints 59 / categories 14 / rate 60/min/ip /
chaos · endpoints that misbehave

HTTP endpoints that misbehave on purpose.

Point your client code, integration tests, or curious colleagues at 59 public endpoints on chaos.catastrophic.io, across 14 categories of adversity — latency, malformed payloads, broken CORS, lying Retry-After headers, and other flavors of wrong. See how your stack handles it before production does.

Endpoints
59
deterministic chaos, hardcoded maxima
Categories
14
latency, payload, auth, cors, etc.
Rate limit
60/min
per IP. don't make me lower it.
Logged data
0 bytes
no bodies, no headers, no params.
chaos · index

14 flavors of wrong

Every category covers a real failure mode your HTTP client should handle gracefully. They probably don't.

chaos · try it

Three quick requests

Quickest way to confirm your client handles adversity. Each one fails (or succeeds-suspiciously) in a documented way.

bash
# 2 second delay before the response arrives
curl -i https://catastrophic.io/slow?ms=2000

# arbitrary status code — try anything from 100 to 599
curl -i https://catastrophic.io/status/503

# 30% chance of failure, otherwise 200
curl -i 'https://catastrophic.io/flaky?p=0.3'
import requests

# 2 second delay before the response arrives
print(requests.get('https://catastrophic.io/slow?ms=2000').status_code)

# arbitrary status code — try anything from 100 to 599
print(requests.get('https://catastrophic.io/status/503').status_code)

# 30% chance of failure, otherwise 200
print(requests.get('https://catastrophic.io/flaky', params={'p': 0.3}).status_code)
// 2 second delay before the response arrives
await fetch('https://catastrophic.io/slow?ms=2000');

// arbitrary status code — try anything from 100 to 599
console.log((await fetch('https://catastrophic.io/status/503')).status);

// 30% chance of failure, otherwise 200
console.log((await fetch('https://catastrophic.io/flaky?p=0.3')).status);
package main

import (
    "fmt"
    "net/http"
)

func main() {
    // 2 second delay before the response arrives
    http.Get("https://catastrophic.io/slow?ms=2000")

    // arbitrary status code — try anything from 100 to 599
    r, _ := http.Get("https://catastrophic.io/status/503")
    fmt.Println(r.StatusCode)

    // 30% chance of failure, otherwise 200
    r, _ = http.Get("https://catastrophic.io/flaky?p=0.3")
    fmt.Println(r.StatusCode)
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
fn main() -> Result<(), Box> {
    // 2 second delay before the response arrives
    reqwest::blocking::get("https://catastrophic.io/slow?ms=2000")?;

    // arbitrary status code — try anything from 100 to 599
    let r = reqwest::blocking::get("https://catastrophic.io/status/503")?;
    println!("{}", r.status());

    // 30% chance of failure, otherwise 200
    println!("{}", reqwest::blocking::get("https://catastrophic.io/flaky?p=0.3")?.status());
    Ok(())
}
import java.net.URI;
import java.net.http.*;

HttpClient c = HttpClient.newHttpClient();
var discard = HttpResponse.BodyHandlers.discarding();

// 2 second delay before the response arrives
c.send(HttpRequest.newBuilder(URI.create("https://catastrophic.io/slow?ms=2000")).build(), discard);

// arbitrary status code — try anything from 100 to 599
System.out.println(c.send(HttpRequest.newBuilder(URI.create("https://catastrophic.io/status/503")).build(), discard).statusCode());

// 30% chance of failure, otherwise 200
System.out.println(c.send(HttpRequest.newBuilder(URI.create("https://catastrophic.io/flaky?p=0.3")).build(), discard).statusCode());
using var c = new HttpClient();

// 2 second delay before the response arrives
await c.GetAsync("https://catastrophic.io/slow?ms=2000");

// arbitrary status code — try anything from 100 to 599
var r = await c.GetAsync("https://catastrophic.io/status/503");
Console.WriteLine((int)r.StatusCode);

// 30% chance of failure, otherwise 200
Console.WriteLine((int)(await c.GetAsync("https://catastrophic.io/flaky?p=0.3")).StatusCode);
require 'net/http'

# 2 second delay before the response arrives
Net::HTTP.get_response(URI('https://catastrophic.io/slow?ms=2000'))

# arbitrary status code — try anything from 100 to 599
puts Net::HTTP.get_response(URI('https://catastrophic.io/status/503')).code

# 30% chance of failure, otherwise 200
puts Net::HTTP.get_response(URI('https://catastrophic.io/flaky?p=0.3')).code
# 2 second delay before the response arrives
Invoke-WebRequest 'https://catastrophic.io/slow?ms=2000'

# arbitrary status code — wrap in try/catch for non-2xx
try { Invoke-WebRequest 'https://catastrophic.io/status/503' } catch { $_.Exception.Response.StatusCode.value__ }

# 30% chance of failure, otherwise 200
try { Invoke-WebRequest 'https://catastrophic.io/flaky?p=0.3' } catch { 'failed (chaos)' }